retracesoftware-proxy 0.1.14__py3-none-any.whl → 0.1.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- retracesoftware/config.json +24 -7
- retracesoftware/install/patcher.py +53 -55
- retracesoftware/proxy/proxysystem.py +13 -3
- retracesoftware/proxy/record.py +16 -16
- retracesoftware/proxy/replay.py +52 -26
- retracesoftware/proxy/thread.py +49 -1
- {retracesoftware_proxy-0.1.14.dist-info → retracesoftware_proxy-0.1.16.dist-info}/METADATA +1 -1
- {retracesoftware_proxy-0.1.14.dist-info → retracesoftware_proxy-0.1.16.dist-info}/RECORD +10 -10
- {retracesoftware_proxy-0.1.14.dist-info → retracesoftware_proxy-0.1.16.dist-info}/WHEEL +0 -0
- {retracesoftware_proxy-0.1.14.dist-info → retracesoftware_proxy-0.1.16.dist-info}/top_level.txt +0 -0
retracesoftware/config.json
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
"internal", {"comment": "Default state when retrace is disabled for a thread"},
|
|
5
5
|
"external", {"comment": "When target thread is running outside the python system to be recorded"},
|
|
6
6
|
"retrace", {"comment": "When target thread is running outside the retrace system"},
|
|
7
|
-
"bootstrap", {"comment": "When the target thread is running in the low-level module load machinery"},
|
|
8
7
|
"gc", {"comment": "When the target thread is running inside the pyton garbage collector"}
|
|
9
8
|
],
|
|
10
9
|
|
|
@@ -157,6 +156,11 @@
|
|
|
157
156
|
},
|
|
158
157
|
|
|
159
158
|
"modules": {
|
|
159
|
+
"_frozen_importlib_external": {
|
|
160
|
+
"with_state": {
|
|
161
|
+
"disabled": ["_path_stat"]
|
|
162
|
+
}
|
|
163
|
+
},
|
|
160
164
|
"_imp": {
|
|
161
165
|
"patch_extension_exec": ["exec_dynamic", "exec_builtin"],
|
|
162
166
|
"comment": {
|
|
@@ -175,6 +179,7 @@
|
|
|
175
179
|
"disabled": ["Bdb.trace_dispatch"]
|
|
176
180
|
}
|
|
177
181
|
},
|
|
182
|
+
|
|
178
183
|
"sys": {
|
|
179
184
|
"with_state": {
|
|
180
185
|
"disabled": ["excepthook"]
|
|
@@ -186,13 +191,21 @@
|
|
|
186
191
|
}
|
|
187
192
|
},
|
|
188
193
|
|
|
189
|
-
"importlib
|
|
194
|
+
"importlib": {
|
|
190
195
|
"with_state": {
|
|
191
|
-
"
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
+
"disabled": ["import_module"]
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
"importlib._bootstrap": {
|
|
201
|
+
"comment": {
|
|
202
|
+
"with_state": {
|
|
203
|
+
"internal": [
|
|
204
|
+
"_load_unlocked",
|
|
205
|
+
"_find_spec",
|
|
206
|
+
"_lock_unlock_module",
|
|
207
|
+
"_get_module_lock"]
|
|
208
|
+
}
|
|
196
209
|
}
|
|
197
210
|
},
|
|
198
211
|
|
|
@@ -233,6 +246,10 @@
|
|
|
233
246
|
"builtins": {
|
|
234
247
|
"patch_hash": ["object"],
|
|
235
248
|
|
|
249
|
+
"with_state": {
|
|
250
|
+
"disabled": ["__import__"]
|
|
251
|
+
},
|
|
252
|
+
|
|
236
253
|
"comment": {
|
|
237
254
|
"replace": {
|
|
238
255
|
"set": "retracesoftware_utils.set",
|
|
@@ -29,6 +29,8 @@ import retracesoftware.utils as utils
|
|
|
29
29
|
|
|
30
30
|
from retracesoftware.install import edgecases
|
|
31
31
|
from functools import partial
|
|
32
|
+
from retracesoftware.proxy.thread import start_new_thread_wrapper
|
|
33
|
+
|
|
32
34
|
# from retrace_utils.intercept import proxy
|
|
33
35
|
|
|
34
36
|
# from retrace_utils.intercept.typeutils import *
|
|
@@ -300,22 +302,29 @@ class Patcher:
|
|
|
300
302
|
|
|
301
303
|
@patch
|
|
302
304
|
def patch_start_new_thread(self, value):
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
305
|
+
return start_new_thread_wrapper(thread_state = self.thread_state,
|
|
306
|
+
on_exit = self.system.on_thread_exit,
|
|
307
|
+
start_new_thread = value)
|
|
308
|
+
|
|
309
|
+
# def start_new_thread(function, *args):
|
|
310
|
+
# # synchronized, replay shoudl yield correct number
|
|
311
|
+
# thread_id = self.thread_counter()
|
|
306
312
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
313
|
+
# def threadrunner(*args, **kwargs):
|
|
314
|
+
# nonlocal thread_id
|
|
315
|
+
# self.system.set_thread_id(thread_id)
|
|
310
316
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
317
|
+
# with self.thread_state.select('internal'):
|
|
318
|
+
# try:
|
|
319
|
+
# # if self.tracing:
|
|
320
|
+
# # FrameTracer.install(self.thread_state.dispatch(noop, internal = self.checkpoint))
|
|
321
|
+
# return function(*args, **kwargs)
|
|
322
|
+
# finally:
|
|
323
|
+
# print(f'exiting: {thread_id}')
|
|
315
324
|
|
|
316
|
-
|
|
325
|
+
# return value(threadrunner, *args)
|
|
317
326
|
|
|
318
|
-
return self.thread_state.dispatch(value, internal = start_new_thread)
|
|
327
|
+
# return self.thread_state.dispatch(value, internal = start_new_thread)
|
|
319
328
|
|
|
320
329
|
@phase
|
|
321
330
|
def wrappers(self, spec, mod_dict):
|
|
@@ -323,39 +332,21 @@ class Patcher:
|
|
|
323
332
|
|
|
324
333
|
@patch
|
|
325
334
|
def patch_exec(self, exec):
|
|
326
|
-
def is_module_exec(source):
|
|
327
|
-
return isinstance(source, types.CodeType) and \
|
|
328
|
-
source.co_name == '<module>' and inspect.getmodule(source)
|
|
329
335
|
|
|
330
|
-
def
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
with self.thread_state.select('disabled'):
|
|
334
|
-
if is_module_exec(source):
|
|
335
|
-
module = inspect.getmodule(source)
|
|
336
|
-
|
|
337
|
-
if module:
|
|
338
|
-
result = exec(source, *args, **kwargs)
|
|
339
|
-
self(module)
|
|
340
|
-
return result
|
|
341
|
-
else:
|
|
342
|
-
return exec(source, *args,**kwargs)
|
|
336
|
+
def exec_wrapper2(source, *args,**kwargs):
|
|
337
|
+
if isinstance(source, types.CodeType) and source.co_name == '<module>':
|
|
338
|
+
self(inspect.getmodule(source))
|
|
343
339
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
# self(module)
|
|
340
|
+
def first(x): return x[0]
|
|
341
|
+
|
|
342
|
+
wrapped_exec = functional.sequence(
|
|
343
|
+
functional.vector(
|
|
344
|
+
self.thread_state.wrap('internal', exec),
|
|
345
|
+
exec_wrapper2),
|
|
346
|
+
first)
|
|
353
347
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
# return exec(source, *args,**kwargs)
|
|
357
|
-
|
|
358
|
-
return self.thread_state.dispatch(exec, internal = exec_wrapper)
|
|
348
|
+
return self.thread_state.dispatch(exec, internal = wrapped_exec)
|
|
349
|
+
|
|
359
350
|
# self.thread_state.wrap(desired_state = 'disabled', function = exec_wrapper)
|
|
360
351
|
|
|
361
352
|
@patch
|
|
@@ -415,7 +406,6 @@ class Patcher:
|
|
|
415
406
|
|
|
416
407
|
@patch
|
|
417
408
|
def patch_hash(self, cls):
|
|
418
|
-
print(f'patching hash for: {cls}')
|
|
419
409
|
utils.patch_hash(cls = cls, hashfunc = self.hashfunc)
|
|
420
410
|
|
|
421
411
|
@patch
|
|
@@ -496,6 +486,8 @@ class Patcher:
|
|
|
496
486
|
|
|
497
487
|
def patch_module_with_name(self, mod_name, module):
|
|
498
488
|
with self.disable:
|
|
489
|
+
print(f'Patching: {module}')
|
|
490
|
+
|
|
499
491
|
self.log('install.module', mod_name)
|
|
500
492
|
|
|
501
493
|
# self.system.log(f'patching module: {mod_name}')
|
|
@@ -520,19 +512,23 @@ class Patcher:
|
|
|
520
512
|
|
|
521
513
|
def __call__(self, module):
|
|
522
514
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
515
|
+
print(f'patcher called with: {module} {self.thread_state.value}')
|
|
516
|
+
|
|
517
|
+
if not hasattr(module, '__retrace__'):
|
|
518
|
+
|
|
519
|
+
print(f'patcher called with: {module} 1')
|
|
526
520
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
521
|
+
configs = list(self.configs(module))
|
|
522
|
+
|
|
523
|
+
if len(configs) > 0:
|
|
524
|
+
if len(configs) > 1:
|
|
525
|
+
raise Exception(f'TODO')
|
|
526
|
+
else:
|
|
527
|
+
module.__retrace__ = None
|
|
528
|
+
try:
|
|
529
|
+
self.patch_module_with_name(configs[0], module)
|
|
530
|
+
except Exception as error:
|
|
531
|
+
raise Exception(f'Error patching module: {configs[0]}') from error
|
|
536
532
|
|
|
537
533
|
return module
|
|
538
534
|
|
|
@@ -629,4 +625,6 @@ def install(mode):
|
|
|
629
625
|
|
|
630
626
|
threading.current_thread().__retrace__ = system
|
|
631
627
|
|
|
628
|
+
# utils.sigtrap(None)
|
|
629
|
+
|
|
632
630
|
return system
|
|
@@ -36,8 +36,12 @@ def resolve(obj):
|
|
|
36
36
|
def is_function_type(cls):
|
|
37
37
|
return cls in [types.BuiltinFunctionType, types.FunctionType]
|
|
38
38
|
|
|
39
|
+
method_types = (types.MethodDescriptorType,
|
|
40
|
+
types.WrapperDescriptorType,
|
|
41
|
+
types.FunctionType)
|
|
42
|
+
|
|
39
43
|
def is_instance_method(obj):
|
|
40
|
-
return isinstance(obj,
|
|
44
|
+
return isinstance(obj, method_types)
|
|
41
45
|
|
|
42
46
|
class ProxySystem:
|
|
43
47
|
|
|
@@ -100,8 +104,8 @@ class ProxySystem:
|
|
|
100
104
|
default = tracer(name, unproxy_execute)
|
|
101
105
|
return thread_state.dispatch(default, internal = internal, external = external)
|
|
102
106
|
|
|
103
|
-
self.ext_handler = self.wrap_int_to_ext(int2ext)
|
|
104
|
-
self.int_handler = self.wrap_ext_to_int(ext2int)
|
|
107
|
+
self.ext_handler = thread_state.wrap('retrace', self.wrap_int_to_ext(int2ext))
|
|
108
|
+
self.int_handler = thread_state.wrap('retrace', self.wrap_ext_to_int(ext2int))
|
|
105
109
|
|
|
106
110
|
self.ext_dispatch = gateway('proxy.int.disabled.event', internal = self.ext_handler)
|
|
107
111
|
self.int_dispatch = gateway('proxy.ext.disabled.event', external = self.int_handler)
|
|
@@ -126,6 +130,9 @@ class ProxySystem:
|
|
|
126
130
|
self.thread_state.value = self.saved_thread_state
|
|
127
131
|
self.fork_counter += 1
|
|
128
132
|
|
|
133
|
+
def on_thread_exit(self, thread_id):
|
|
134
|
+
pass
|
|
135
|
+
|
|
129
136
|
# def create_stub(self): return False
|
|
130
137
|
|
|
131
138
|
def int_proxytype(self, cls):
|
|
@@ -156,10 +163,13 @@ class ProxySystem:
|
|
|
156
163
|
return utils.wrapped_function(handler = self.ext_handler, target = obj)
|
|
157
164
|
|
|
158
165
|
def patchtype(self, cls):
|
|
166
|
+
print(f'Proxying type: {cls}')
|
|
167
|
+
|
|
159
168
|
if cls in self.immutable_types or issubclass(cls, tuple):
|
|
160
169
|
return cls
|
|
161
170
|
|
|
162
171
|
def wrap(func):
|
|
172
|
+
print(f'Wrapping: {cls.__name__}.{func.__name__}')
|
|
163
173
|
return self.thread_state.dispatch(func, internal = self.proxy_function(func))
|
|
164
174
|
|
|
165
175
|
def wrap_new(func):
|
retracesoftware/proxy/record.py
CHANGED
|
@@ -5,7 +5,7 @@ import retracesoftware.stream as stream
|
|
|
5
5
|
from retracesoftware.proxy.proxytype import *
|
|
6
6
|
# from retracesoftware.proxy.gateway import gateway_pair
|
|
7
7
|
from retracesoftware.proxy.proxysystem import ProxySystem
|
|
8
|
-
from retracesoftware.proxy.thread import write_thread_switch, ThreadSwitch
|
|
8
|
+
from retracesoftware.proxy.thread import write_thread_switch, ThreadSwitch, thread_id
|
|
9
9
|
from retracesoftware.install.tracer import Tracer
|
|
10
10
|
from retracesoftware.proxy.stubfactory import StubRef, ExtendedRef
|
|
11
11
|
from retracesoftware.proxy.globalref import GlobalRef
|
|
@@ -87,16 +87,16 @@ class RecordProxySystem(ProxySystem):
|
|
|
87
87
|
|
|
88
88
|
self.pid = self.getpid()
|
|
89
89
|
|
|
90
|
-
self.writer = stream.writer(path)
|
|
90
|
+
self.writer = stream.writer(path = path, thread = thread_id)
|
|
91
91
|
|
|
92
|
-
def on_switch():
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
# def on_switch():
|
|
93
|
+
# print(f"On thread switch!!!")
|
|
94
|
+
# # print(f"On thread switch!!!: {utils.thread_id().id}")
|
|
95
|
+
# # utils.sigtrap(utils.thread_id())
|
|
96
|
+
# self.writer(utils.thread_id())
|
|
97
|
+
# # utils.sigtrap(utils.thread_id())
|
|
98
98
|
|
|
99
|
-
write = utils.observer(on_call = utils.thread_switch_monitor(on_switch), function = self.writer)
|
|
99
|
+
# write = utils.observer(on_call = utils.thread_switch_monitor(on_switch), function = self.writer)
|
|
100
100
|
|
|
101
101
|
# w = self.writer.handle('TRACE')
|
|
102
102
|
# def trace_writer(*args):
|
|
@@ -121,15 +121,15 @@ class RecordProxySystem(ProxySystem):
|
|
|
121
121
|
|
|
122
122
|
# self.sync = lambda function: functional.firstof(self.thread_switch_monitor, functional.always(self.writer.handle('SYNC')), function)
|
|
123
123
|
|
|
124
|
+
sync_handle = self.writer.handle('SYNC')
|
|
125
|
+
|
|
124
126
|
self.sync = lambda function: \
|
|
125
|
-
utils.observer(
|
|
126
|
-
on_call = functional.lazy(write, self.writer.handle('SYNC')),
|
|
127
|
-
function = function)
|
|
127
|
+
utils.observer(on_call = functional.lazy(sync_handle), function = function)
|
|
128
128
|
|
|
129
129
|
error = self.writer.handle('ERROR')
|
|
130
130
|
|
|
131
131
|
def write_error(cls, val, traceback):
|
|
132
|
-
|
|
132
|
+
error(cls, val)
|
|
133
133
|
|
|
134
134
|
# self.set_thread_id = functional.partial(utils.set_thread_id, self.writer)
|
|
135
135
|
|
|
@@ -139,13 +139,13 @@ class RecordProxySystem(ProxySystem):
|
|
|
139
139
|
# w(self.writer.messages_written, name, *args)
|
|
140
140
|
|
|
141
141
|
# tracer = Tracer(tracing_config, writer = foo)
|
|
142
|
-
tracer = Tracer(tracing_config, writer =
|
|
142
|
+
tracer = Tracer(tracing_config, writer = self.writer.handle('TRACE'))
|
|
143
143
|
|
|
144
144
|
# self.wrap_int_to_ext = self.sync
|
|
145
145
|
|
|
146
|
-
self.on_int_call = functional.mapargs(transform = serialize, function =
|
|
146
|
+
self.on_int_call = functional.mapargs(transform = serialize, function = self.writer.handle('CALL'))
|
|
147
147
|
|
|
148
|
-
self.on_ext_result = functional.sequence(serialize,
|
|
148
|
+
self.on_ext_result = functional.sequence(serialize, self.writer.handle('RESULT'))
|
|
149
149
|
|
|
150
150
|
self.on_ext_error = write_error
|
|
151
151
|
|
retracesoftware/proxy/replay.py
CHANGED
|
@@ -3,7 +3,7 @@ import retracesoftware_utils as utils
|
|
|
3
3
|
import retracesoftware.stream as stream
|
|
4
4
|
|
|
5
5
|
from retracesoftware.install.tracer import Tracer
|
|
6
|
-
from retracesoftware.proxy.thread import per_thread_messages
|
|
6
|
+
from retracesoftware.proxy.thread import per_thread_messages, thread_id
|
|
7
7
|
from retracesoftware.proxy.proxytype import *
|
|
8
8
|
# from retracesoftware.proxy.gateway import gateway_pair
|
|
9
9
|
from retracesoftware.proxy.record import StubRef, Placeholder
|
|
@@ -15,6 +15,7 @@ import os
|
|
|
15
15
|
import weakref
|
|
16
16
|
import traceback
|
|
17
17
|
import pprint
|
|
18
|
+
|
|
18
19
|
from itertools import count, islice
|
|
19
20
|
|
|
20
21
|
# we can have a dummy method descriptor, its has a __name__ and when called, returns the next element
|
|
@@ -61,6 +62,8 @@ def on_stack_mismatch(last_matching, record, replay):
|
|
|
61
62
|
print('Record stacktrace:')
|
|
62
63
|
for line in islice(record, 0, len(record) - matching):
|
|
63
64
|
print(line)
|
|
65
|
+
|
|
66
|
+
print(f'-----------')
|
|
64
67
|
else:
|
|
65
68
|
matching = count_matching(reversed(record), reversed(replay))
|
|
66
69
|
|
|
@@ -75,36 +78,52 @@ def on_stack_mismatch(last_matching, record, replay):
|
|
|
75
78
|
print('Record stacktrace:')
|
|
76
79
|
for line in islice(record, 0, len(record) - matching):
|
|
77
80
|
print(line)
|
|
81
|
+
|
|
78
82
|
|
|
79
83
|
|
|
80
84
|
class ReplayProxySystem(ProxySystem):
|
|
81
85
|
|
|
82
86
|
@utils.striptraceback
|
|
83
87
|
def next_result(self):
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
try:
|
|
89
|
+
while True:
|
|
90
|
+
next = self.messages()
|
|
91
|
+
|
|
92
|
+
if next == 'CALL':
|
|
93
|
+
func = self.messages()
|
|
94
|
+
args = self.messages()
|
|
95
|
+
kwargs = self.messages()
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
func(*args, **kwargs)
|
|
99
|
+
except:
|
|
100
|
+
pass
|
|
101
|
+
|
|
102
|
+
elif next == 'RESULT':
|
|
103
|
+
return self.messages()
|
|
104
|
+
|
|
105
|
+
elif next == 'ERROR':
|
|
106
|
+
# breakpoint()
|
|
107
|
+
err_type = self.messages()
|
|
108
|
+
err_value = self.messages()
|
|
109
|
+
utils.raise_exception(err_type, err_value)
|
|
110
|
+
else:
|
|
111
|
+
assert type(next) is not str
|
|
112
|
+
return next
|
|
113
|
+
except TimeoutError:
|
|
114
|
+
print(f'timeout for reader, active thread: {self.reader.active_thread}, next_control: {self.reader.next_control}')
|
|
86
115
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
args = self.messages()
|
|
90
|
-
kwargs = self.messages()
|
|
116
|
+
for thread,stack in self.reader.stacktraces.items():
|
|
117
|
+
print(f'thread: {thread}')
|
|
91
118
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
119
|
+
formatted_frames = [
|
|
120
|
+
(frame.filename, frame.lineno, frame.function, frame.code_context[0].strip() if frame.code_context else None)
|
|
121
|
+
for frame in stack
|
|
122
|
+
]
|
|
123
|
+
formatted_trace = traceback.format_list(formatted_frames)
|
|
124
|
+
print("Traceback (most recent call last):\n" + "".join(formatted_trace))
|
|
96
125
|
|
|
97
|
-
|
|
98
|
-
return self.messages()
|
|
99
|
-
|
|
100
|
-
elif next == 'ERROR':
|
|
101
|
-
# breakpoint()
|
|
102
|
-
err_type = self.messages()
|
|
103
|
-
err_value = self.messages()
|
|
104
|
-
utils.raise_exception(err_type, err_value)
|
|
105
|
-
else:
|
|
106
|
-
assert type(next) is not str
|
|
107
|
-
return next
|
|
126
|
+
utils.sigtrap(None)
|
|
108
127
|
|
|
109
128
|
def bind(self, obj):
|
|
110
129
|
read = self.messages()
|
|
@@ -138,7 +157,6 @@ class ReplayProxySystem(ProxySystem):
|
|
|
138
157
|
def basetype(self, cls):
|
|
139
158
|
return self.stub_factory.create_stubtype(StubRef(cls))
|
|
140
159
|
|
|
141
|
-
|
|
142
160
|
def readnext(self):
|
|
143
161
|
with self.thread_state.select('disabled'):
|
|
144
162
|
try:
|
|
@@ -201,6 +219,11 @@ class ReplayProxySystem(ProxySystem):
|
|
|
201
219
|
for arg in args:
|
|
202
220
|
self.read_required(arg)
|
|
203
221
|
|
|
222
|
+
def on_thread_exit(self, thread_id):
|
|
223
|
+
print(f'on_thread_exit!!!!')
|
|
224
|
+
self.reader.wake_pending()
|
|
225
|
+
|
|
226
|
+
|
|
204
227
|
def __init__(self,
|
|
205
228
|
thread_state,
|
|
206
229
|
immutable_types,
|
|
@@ -209,8 +232,11 @@ class ReplayProxySystem(ProxySystem):
|
|
|
209
232
|
fork_path = []):
|
|
210
233
|
|
|
211
234
|
# self.messages_read = 0
|
|
212
|
-
self.reader = stream.reader(path)
|
|
213
235
|
|
|
236
|
+
self.reader = stream.reader(path,
|
|
237
|
+
thread = thread_id,
|
|
238
|
+
timeout_seconds = 5)
|
|
239
|
+
|
|
214
240
|
self.bindings = utils.id_dict()
|
|
215
241
|
# self.set_thread_id = utils.set_thread_id
|
|
216
242
|
self.fork_path = fork_path
|
|
@@ -235,9 +261,9 @@ class ReplayProxySystem(ProxySystem):
|
|
|
235
261
|
print(f'Error reading next result: {error}')
|
|
236
262
|
raise(error)
|
|
237
263
|
|
|
238
|
-
self.messages = functional.sequence(per_thread_messages(foo), deserialize)
|
|
264
|
+
# self.messages = functional.sequence(per_thread_messages(foo), deserialize)
|
|
239
265
|
|
|
240
|
-
|
|
266
|
+
self.messages = functional.sequence(self.reader, deserialize)
|
|
241
267
|
|
|
242
268
|
self.stub_factory = StubFactory(thread_state = thread_state, next_result = self.next_result)
|
|
243
269
|
|
retracesoftware/proxy/thread.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import retracesoftware.functional as functional
|
|
2
2
|
import retracesoftware_utils as utils
|
|
3
3
|
|
|
4
|
+
import os
|
|
5
|
+
import _thread
|
|
6
|
+
|
|
4
7
|
# def thread_aware_writer(writer):
|
|
5
8
|
# on_thread_switch = functional.sequence(utils.thread_id(), writer.handle('THREAD_SWITCH'))
|
|
6
9
|
# return utils.threadawareproxy(on_thread_switch = on_thread_switch, target = writer)
|
|
@@ -39,6 +42,7 @@ def prefix_with_thread_id(f, thread_id):
|
|
|
39
42
|
current = obj.id
|
|
40
43
|
obj = f()
|
|
41
44
|
|
|
45
|
+
# print(f'prefix_with_thread_id: {(current, obj)}')
|
|
42
46
|
return (current, obj)
|
|
43
47
|
|
|
44
48
|
return next
|
|
@@ -47,8 +51,15 @@ def per_thread_messages(messages):
|
|
|
47
51
|
thread_id = utils.thread_id
|
|
48
52
|
# thread_id = lambda: 'FOOOOO!!!'
|
|
49
53
|
|
|
54
|
+
def on_timeout(demux, key):
|
|
55
|
+
print(f'ON TIMEOUT!!!! {key} pending: {demux.pending} {demux.pending_keys}')
|
|
56
|
+
utils.sigtrap(demux)
|
|
57
|
+
os._exit(1)
|
|
58
|
+
|
|
50
59
|
demux = utils.demux(source = prefix_with_thread_id(messages, thread_id),
|
|
51
|
-
key_function = lambda obj: obj[0]
|
|
60
|
+
key_function = lambda obj: obj[0],
|
|
61
|
+
timeout_seconds = 60,
|
|
62
|
+
on_timeout = on_timeout)
|
|
52
63
|
|
|
53
64
|
# def next():
|
|
54
65
|
# thread,message = demux(thread_id())
|
|
@@ -56,3 +67,40 @@ def per_thread_messages(messages):
|
|
|
56
67
|
|
|
57
68
|
# return next
|
|
58
69
|
return functional.repeatedly(lambda: demux(thread_id())[1])
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# _thread.start_new_thread(function, args[, kwargs])
|
|
73
|
+
counters = _thread._local()
|
|
74
|
+
counters.id = ()
|
|
75
|
+
counters.counter = 0
|
|
76
|
+
|
|
77
|
+
def with_thread_id(thread_id, on_exit, function):
|
|
78
|
+
def on_call(*args, **kwargs):
|
|
79
|
+
counters.id = thread_id
|
|
80
|
+
counters.counter = 0
|
|
81
|
+
|
|
82
|
+
def on_result(res):
|
|
83
|
+
on_exit(thread_id)
|
|
84
|
+
|
|
85
|
+
def on_error(*args):
|
|
86
|
+
on_exit(thread_id)
|
|
87
|
+
|
|
88
|
+
return utils.observer(on_call = on_call, on_result = on_result, on_error = on_error, function = function)
|
|
89
|
+
|
|
90
|
+
thread_id = functional.lazy(getattr, counters, 'id')
|
|
91
|
+
|
|
92
|
+
def start_new_thread_wrapper(thread_state, on_exit, start_new_thread):
|
|
93
|
+
|
|
94
|
+
def wrapper(function, *args):
|
|
95
|
+
|
|
96
|
+
next_id = counters.id + (counters.counter,)
|
|
97
|
+
counters.counter += 1
|
|
98
|
+
|
|
99
|
+
wrapped_function = with_thread_id(thread_id = next_id,
|
|
100
|
+
on_exit = on_exit,
|
|
101
|
+
function = thread_state.wrap('internal', function))
|
|
102
|
+
|
|
103
|
+
return start_new_thread(wrapped_function, *args)
|
|
104
|
+
|
|
105
|
+
return thread_state.dispatch(start_new_thread, internal = wrapper)
|
|
106
|
+
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
retracesoftware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
retracesoftware/config.json,sha256=
|
|
2
|
+
retracesoftware/config.json,sha256=kV7FMjIQodixCx35I-3JIivOgRd_BzGJgpx_2naw-K4,9229
|
|
3
3
|
retracesoftware/config.yaml,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
retracesoftware/install/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
retracesoftware/install/config.py,sha256=EzE5ifQF2lo--hu2njI4T0FJ-zlnWDJV6i7x0DMkVTw,1364
|
|
6
6
|
retracesoftware/install/edgecases.py,sha256=NR3lyvad9sRsyeDv_Ya8V4xMgPsMPOi9rMcnFOJGOEA,6330
|
|
7
7
|
retracesoftware/install/globals.py,sha256=F8XvIoZQQ10gSRalk30dvdKllxlwxkaggYY6FogLDxY,510
|
|
8
8
|
retracesoftware/install/install.py,sha256=HCD_ji8XCr96b5fNzNdL_8qcEp0Jf05Em7T6GA6u8HU,4969
|
|
9
|
-
retracesoftware/install/patcher.py,sha256=
|
|
9
|
+
retracesoftware/install/patcher.py,sha256=b_VSG7EG1hhFh1VsAV2dHDRCiABpnEXvX_o5bsQXCDA,20268
|
|
10
10
|
retracesoftware/install/predicate.py,sha256=tX7NQc0rGkyyHYO3mduYHcJHbw1wczT53m_Dpkzo6do,2679
|
|
11
11
|
retracesoftware/install/record.py,sha256=R2GOIA_WAggrNmVwZJh9r1xp-GVu43iKq-ykQ1VKEHE,3408
|
|
12
12
|
retracesoftware/install/references.py,sha256=A-G651IDOfuo00MkbAdpbIQh_15ChvJ7uAVTSmE6zd4,1721
|
|
@@ -17,13 +17,13 @@ retracesoftware/proxy/__init__.py,sha256=ntIyqKhBRkKEkcW_oOPodikh-mxYl8OXRnSaj-9
|
|
|
17
17
|
retracesoftware/proxy/gateway.py,sha256=xESohWXkiNm4ZutU0RgWUwxjxcBWRQ4rQyxIGQXv_F4,1590
|
|
18
18
|
retracesoftware/proxy/globalref.py,sha256=yXtJsOeBHN9xoEgJWA3MJco-jD2SQUef_fDatA4A6rg,803
|
|
19
19
|
retracesoftware/proxy/proxyfactory.py,sha256=qhOqDfMJnLDNkQs26JqDB431MwjjRhGQi8xupJ45asg,12272
|
|
20
|
-
retracesoftware/proxy/proxysystem.py,sha256=
|
|
20
|
+
retracesoftware/proxy/proxysystem.py,sha256=8PTljvtxb0PEqYElaGREAfEgR5EpqDhutpttFox6vWg,7858
|
|
21
21
|
retracesoftware/proxy/proxytype.py,sha256=hP-1vJmWBa9KgZFB3CnZy0UbC4u8Wr2e76lGI0JM2SA,12992
|
|
22
|
-
retracesoftware/proxy/record.py,sha256=
|
|
23
|
-
retracesoftware/proxy/replay.py,sha256=
|
|
22
|
+
retracesoftware/proxy/record.py,sha256=47vhAYIUrR2bWo-rQ9xU_Xyg3kNrA5Lqq4-8Cxg4-zg,5463
|
|
23
|
+
retracesoftware/proxy/replay.py,sha256=RWfmTrbeLFCSvV26ow1iwitf1wWt6XfypMcKIxYXZEg,9669
|
|
24
24
|
retracesoftware/proxy/stubfactory.py,sha256=37UX1r8HCAbASTwPdz8QKCrg72NQmM5PsiCho7N2nzg,5129
|
|
25
|
-
retracesoftware/proxy/thread.py,sha256=
|
|
26
|
-
retracesoftware_proxy-0.1.
|
|
27
|
-
retracesoftware_proxy-0.1.
|
|
28
|
-
retracesoftware_proxy-0.1.
|
|
29
|
-
retracesoftware_proxy-0.1.
|
|
25
|
+
retracesoftware/proxy/thread.py,sha256=T1ME6DHB8O0xVnX3Rt1lMl7oCJ2Y0aoFT91D76yNICk,3073
|
|
26
|
+
retracesoftware_proxy-0.1.16.dist-info/METADATA,sha256=zTBolyYWW1whamxpNcJQR32CR3rP4XWQM2zmEoZuAWE,203
|
|
27
|
+
retracesoftware_proxy-0.1.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
28
|
+
retracesoftware_proxy-0.1.16.dist-info/top_level.txt,sha256=hYHsR6txLidmqvjBMITpIHvmJJbmoCAgr76-IpZPRz8,16
|
|
29
|
+
retracesoftware_proxy-0.1.16.dist-info/RECORD,,
|
|
File without changes
|
{retracesoftware_proxy-0.1.14.dist-info → retracesoftware_proxy-0.1.16.dist-info}/top_level.txt
RENAMED
|
File without changes
|