-
Notifications
You must be signed in to change notification settings - Fork 0
/
controlled_threading.py
118 lines (85 loc) · 3.47 KB
/
controlled_threading.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# Populate namespace with default objects from threading and modify as needed
from threading import * #@UnusedWildImport
import threading as original_threading
import greenlet
greenlet_list = []
control_greenlet = greenlet.getcurrent()
def get_greenlet_list():
return greenlet_list
def are_greenlets_alive():
live_greenlets = [greenlet for greenlet in greenlet_list if not greenlet.dead]
return len(live_greenlets) != 0
def start_greenlet_from_file(filename, execution_path_to_run=None):
cancel_all_greenlets()
def run_as_main(filename):
# modify globals so it looks like filename is being run as main
g = globals()
g['__name__'] = '__main__'
# execute file with modified globals dictionary
execfile(filename, g)
new_greenlet = greenlet.greenlet(run_as_main)
greenlet_list.append(new_greenlet)
new_greenlet.switch(filename)
last_greenlet_run = new_greenlet
if execution_path_to_run:
for step in execution_path_to_run:
last_greenlet_run = greenlet_list[step].switch()
return last_greenlet_run
def cancel_all_greenlets():
for greenlet in greenlet_list[:]: # use copy since this loop will modify the contents
if greenlet:
try:
greenlet.throw(KeyboardInterrupt)
except KeyboardInterrupt:
pass
greenlet_list.remove(greenlet)
class Thread(object):
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
self.group = group
self.target = target
self.name = name
self.args = args
self.kwargs = kwargs
self.greenlet = None
self.spawning_greenlet = None
def start(self):
# create greenlet and then "run" it
self.spawning_greenlet = greenlet.getcurrent()
self.greenlet = greenlet.greenlet(run=self.run, parent=control_greenlet)
greenlet_list.append(self.greenlet)
# switch to control greenlet will be simulated as having occurred
# before the spawned greenlet is begun (below) by having the spawned
# greenlet's first action be to switch back to the control thread and
# make it look like the switch occurred from the spawning greenlet
# This is done so that when the controlling greenlet makes its decision
# the spawned greenlet has already been made active and is ready to
# run
# begin greenlet execution
self.greenlet.switch()
def run(self):
# switch to control greenlet so that scheduling can be forced (see note in __init__)
control_greenlet.switch(self.spawning_greenlet)
# begin actual execution
self.target(*self.args, **self.kwargs)
def join(self):
while self.isAlive():
control_greenlet.switch(greenlet.getcurrent())
def isAlive(self):
return not self.greenlet.dead
class Lock(object):
def __init__(self):
self.lock = original_threading.Lock()
def __enter__(self):
self.acquire()
def __exit__(self, exc_type, exc_val, exc_tb):
self.release()
return False
def acquire(self, blocking=1):
control_greenlet.switch(greenlet.getcurrent())
return self.lock.acquire(blocking)
def release(self):
return self.lock.release()
# Python apparently expects the 'threading' module to have a _shutdown method
# without this you'll always get an error on exit
def _shutdown():
pass