retracesoftware-proxy 0.1.14__py3-none-any.whl → 0.1.15__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 +19 -7
- retracesoftware/install/patcher.py +52 -56
- retracesoftware/proxy/proxysystem.py +7 -2
- 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.15.dist-info}/METADATA +1 -1
- {retracesoftware_proxy-0.1.14.dist-info → retracesoftware_proxy-0.1.15.dist-info}/RECORD +10 -10
- {retracesoftware_proxy-0.1.14.dist-info → retracesoftware_proxy-0.1.15.dist-info}/WHEEL +0 -0
- {retracesoftware_proxy-0.1.14.dist-info → retracesoftware_proxy-0.1.15.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
|
|
|
@@ -175,6 +174,7 @@
|
|
|
175
174
|
"disabled": ["Bdb.trace_dispatch"]
|
|
176
175
|
}
|
|
177
176
|
},
|
|
177
|
+
|
|
178
178
|
"sys": {
|
|
179
179
|
"with_state": {
|
|
180
180
|
"disabled": ["excepthook"]
|
|
@@ -186,13 +186,21 @@
|
|
|
186
186
|
}
|
|
187
187
|
},
|
|
188
188
|
|
|
189
|
-
"importlib
|
|
189
|
+
"importlib": {
|
|
190
190
|
"with_state": {
|
|
191
|
-
"
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
191
|
+
"disabled": ["import_module"]
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
"importlib._bootstrap": {
|
|
196
|
+
"comment": {
|
|
197
|
+
"with_state": {
|
|
198
|
+
"internal": [
|
|
199
|
+
"_load_unlocked",
|
|
200
|
+
"_find_spec",
|
|
201
|
+
"_lock_unlock_module",
|
|
202
|
+
"_get_module_lock"]
|
|
203
|
+
}
|
|
196
204
|
}
|
|
197
205
|
},
|
|
198
206
|
|
|
@@ -233,6 +241,10 @@
|
|
|
233
241
|
"builtins": {
|
|
234
242
|
"patch_hash": ["object"],
|
|
235
243
|
|
|
244
|
+
"with_state": {
|
|
245
|
+
"disabled": ["__import__"]
|
|
246
|
+
},
|
|
247
|
+
|
|
236
248
|
"comment": {
|
|
237
249
|
"replace": {
|
|
238
250
|
"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
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
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')
|
|
520
|
+
|
|
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
|
|
|
@@ -100,8 +100,8 @@ class ProxySystem:
|
|
|
100
100
|
default = tracer(name, unproxy_execute)
|
|
101
101
|
return thread_state.dispatch(default, internal = internal, external = external)
|
|
102
102
|
|
|
103
|
-
self.ext_handler = self.wrap_int_to_ext(int2ext)
|
|
104
|
-
self.int_handler = self.wrap_ext_to_int(ext2int)
|
|
103
|
+
self.ext_handler = thread_state.wrap('retrace', self.wrap_int_to_ext(int2ext))
|
|
104
|
+
self.int_handler = thread_state.wrap('retrace', self.wrap_ext_to_int(ext2int))
|
|
105
105
|
|
|
106
106
|
self.ext_dispatch = gateway('proxy.int.disabled.event', internal = self.ext_handler)
|
|
107
107
|
self.int_dispatch = gateway('proxy.ext.disabled.event', external = self.int_handler)
|
|
@@ -126,6 +126,9 @@ class ProxySystem:
|
|
|
126
126
|
self.thread_state.value = self.saved_thread_state
|
|
127
127
|
self.fork_counter += 1
|
|
128
128
|
|
|
129
|
+
def on_thread_exit(self, thread_id):
|
|
130
|
+
pass
|
|
131
|
+
|
|
129
132
|
# def create_stub(self): return False
|
|
130
133
|
|
|
131
134
|
def int_proxytype(self, cls):
|
|
@@ -156,6 +159,8 @@ class ProxySystem:
|
|
|
156
159
|
return utils.wrapped_function(handler = self.ext_handler, target = obj)
|
|
157
160
|
|
|
158
161
|
def patchtype(self, cls):
|
|
162
|
+
print(f'Proxying type: {cls}')
|
|
163
|
+
|
|
159
164
|
if cls in self.immutable_types or issubclass(cls, tuple):
|
|
160
165
|
return cls
|
|
161
166
|
|
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=yMAD8410r8VEnBToXNmtfaBz6MClBVEiKsq6vKgSI0c,9121
|
|
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=_J8YTDd0QNLgURRyrUFikNsImgMOBhCv8Nmps5rjkZI,20241
|
|
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=ttzHcNH4O2GrlTjy3R386HTwRY7Z5QKWbMt6BOf7Jto,7722
|
|
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.15.dist-info/METADATA,sha256=5EIkVm31Txgu2-FN94NLguxj4YtbZ7pU_VaZLisxhCE,203
|
|
27
|
+
retracesoftware_proxy-0.1.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
28
|
+
retracesoftware_proxy-0.1.15.dist-info/top_level.txt,sha256=hYHsR6txLidmqvjBMITpIHvmJJbmoCAgr76-IpZPRz8,16
|
|
29
|
+
retracesoftware_proxy-0.1.15.dist-info/RECORD,,
|
|
File without changes
|
{retracesoftware_proxy-0.1.14.dist-info → retracesoftware_proxy-0.1.15.dist-info}/top_level.txt
RENAMED
|
File without changes
|