35
36:- module(thread_util,
37 [ thread_run_interactor/0, 38 threads/0, 39 join_threads/0, 40 interactor/0, 41 interactor/1, 42 thread_has_console/0, 43 attach_console/0, 44 attach_console/1, 45
46 tspy/1, 47 tspy/2, 48 tdebug/0,
49 tdebug/1, 50 tnodebug/0,
51 tnodebug/1, 52 tprofile/1 53 ]). 54:- use_module(library(apply)). 55:- use_module(library(lists)). 56:- set_prolog_flag(generate_debug_info, false). 57
58:- module_transparent
59 tspy/1,
60 tspy/2. 61
69
73
74threads :-
75 threads(Threads),
76 print_message(information, threads(Threads)).
77
78threads(Threads) :-
79 findall(Thread, thread_statistics(_,Thread), Threads).
80
84
85join_threads :-
86 findall(Ripped, rip_thread(Ripped), AllRipped),
87 ( AllRipped == []
88 -> true
89 ; print_message(informational, joined_threads(AllRipped))
90 ).
91
92rip_thread(thread{id:id, status:Status}) :-
93 thread_property(Id, status(Status)),
94 Status \== running,
95 \+ thread_self(Id),
96 thread_join(Id, _).
97
103
104interactor :-
105 interactor(_).
106
107interactor(Title) :-
108 thread_self(Me),
109 thread_create(thread_run_interactor(Me, Title), _Id,
110 [ detached(true),
111 debug(false)
112 ]),
113 thread_get_message(title(Title)).
114
115thread_run_interactor(Creator, Title) :-
116 set_prolog_flag(query_debug_settings, debug(false, false)),
117 attach_console(Title),
118 thread_send_message(Creator, title(Title)),
119 print_message(banner, thread_welcome),
120 prolog.
121
125
126thread_run_interactor :-
127 set_prolog_flag(query_debug_settings, debug(false, false)),
128 attach_console(_Title),
129 print_message(banner, thread_welcome),
130 prolog.
131
137
138:- dynamic
139 has_console/4. 140
141thread_has_console(main) :- !. 142thread_has_console(Id) :-
143 has_console(Id, _, _, _).
144
145thread_has_console :-
146 current_prolog_flag(break_level, _),
147 !.
148thread_has_console :-
149 thread_self(Id),
150 thread_has_console(Id),
151 !.
152
159
160attach_console :-
161 attach_console(_).
162
163attach_console(_) :-
164 thread_has_console,
165 !.
166attach_console(Title) :-
167 thread_self(Id),
168 ( var(Title)
169 -> console_title(Id, Title)
170 ; true
171 ),
172 open_console(Title, In, Out, Err),
173 assert(has_console(Id, In, Out, Err)),
174 set_stream(In, alias(user_input)),
175 set_stream(Out, alias(user_output)),
176 set_stream(Err, alias(user_error)),
177 set_stream(In, alias(current_input)),
178 set_stream(Out, alias(current_output)),
179 enable_line_editing(In,Out,Err),
180 thread_at_exit(detach_console(Id)).
181
182console_title(Thread, Title) :- 183 current_prolog_flag(console_menu_version, qt),
184 !,
185 human_thread_id(Thread, Id),
186 format(atom(Title), 'Thread ~w', [Id]).
187console_title(Thread, Title) :-
188 current_prolog_flag(system_thread_id, SysId),
189 human_thread_id(Thread, Id),
190 format(atom(Title),
191 'SWI-Prolog Thread ~w (~d) Interactor',
192 [Id, SysId]).
193
194human_thread_id(Thread, Alias) :-
195 thread_property(Thread, alias(Alias)),
196 !.
197human_thread_id(Thread, Id) :-
198 thread_property(Thread, id(Id)).
199
204
205:- multifile xterm_args/1. 206:- dynamic xterm_args/1. 207
208:- if(current_predicate(win_open_console/5)). 209
210open_console(Title, In, Out, Err) :-
211 thread_self(Id),
212 regkey(Id, Key),
213 win_open_console(Title, In, Out, Err,
214 [ registry_key(Key)
215 ]).
216
217regkey(Key, Key) :-
218 atom(Key).
219regkey(_, 'Anonymous').
220
221:- else. 222
233
234xterm_args(['-xrm', '*backarrowKeyIsErase: false']).
235xterm_args(['-xrm', '*backarrowKey: false']).
236xterm_args(['-fa', 'monospace;pixelsize=11;regular']).
237xterm_args(['-fg', '#000000']).
238xterm_args(['-bg', '#ffffdd']).
239xterm_args(['-sb', '-sl', 1000, '-rightbar']).
240
241open_console(Title, In, Out, Err) :-
242 findall(Arg, xterm_args(Arg), Args),
243 append(Args, Argv),
244 open_xterm(Title, In, Out, Err, Argv).
245
246:- endif. 247
253
254:- if((current_prolog_flag(readline, editline),
255 exists_source(library(editline)))). 256:- use_module(library(editline)). 257enable_line_editing(_In, _Out, _Err) :-
258 current_prolog_flag(readline, editline),
259 !,
260 el_wrap.
261:- endif. 262enable_line_editing(_In, _Out, _Err).
263
264:- if(current_predicate(el_unwrap/1)). 265disable_line_editing(_In, _Out, _Err) :-
266 el_unwrap(user_input).
267:- endif. 268disable_line_editing(_In, _Out, _Err).
269
270
274
275detach_console(Id) :-
276 ( retract(has_console(Id, In, Out, Err))
277 -> disable_line_editing(In, Out, Err),
278 close(In, [force(true)]),
279 close(Out, [force(true)]),
280 close(Err, [force(true)])
281 ; true
282 ).
283
284
285 288
294
295tspy(Spec) :-
296 spy(Spec),
297 tdebug.
298
299tspy(Spec, ThreadID) :-
300 spy(Spec),
301 tdebug(ThreadID).
302
303
309
310tdebug :-
311 forall(debug_target(Id), thread_signal(Id, gdebug)).
312
313tdebug(ThreadID) :-
314 thread_signal(ThreadID, gdebug).
315
320
321tnodebug :-
322 forall(debug_target(Id), thread_signal(Id, nodebug)).
323
324tnodebug(ThreadID) :-
325 thread_signal(ThreadID, nodebug).
326
327
328debug_target(Thread) :-
329 thread_property(Thread, status(running)),
330 thread_property(Thread, debug(true)).
331
332
333 336
340
341tprofile(Thread) :-
342 init_pce,
343 thread_signal(Thread,
344 ( reset_profiler,
345 profiler(_, true)
346 )),
347 format('Running profiler in thread ~w (press RET to show results) ...',
348 [Thread]),
349 flush_output,
350 get0(_),
351 thread_signal(Thread,
352 ( profiler(_, false),
353 show_profile([])
354 )).
355
356
361
362init_pce :-
363 current_prolog_flag(gui, true),
364 !,
365 call(send(@(display), open)). 366init_pce.
367
368
369 372
373:- multifile
374 user:message_hook/3. 375
376user:message_hook(trace_mode(on), _, Lines) :-
377 \+ thread_has_console,
378 \+ current_prolog_flag(gui_tracer, true),
379 catch(attach_console, _, fail),
380 print_message_lines(user_error, '% ', Lines).
381
382:- multifile
383 prolog:message/3. 384
385prolog:message(thread_welcome) -->
386 { thread_self(Self),
387 human_thread_id(Self, Id)
388 },
389 [ 'SWI-Prolog console for thread ~w'-[Id],
390 nl, nl
391 ].
392prolog:message(joined_threads(Threads)) -->
393 [ 'Joined the following threads'-[], nl ],
394 thread_list(Threads).
395prolog:message(threads(Threads)) -->
396 thread_list(Threads).
397
398thread_list(Threads) -->
399 { maplist(th_id_len, Threads, Lens),
400 max_list(Lens, MaxWidth),
401 LeftColWidth is max(6, MaxWidth),
402 Threads = [H|_]
403 },
404 thread_list_header(H, LeftColWidth),
405 thread_list(Threads, LeftColWidth).
406
407th_id_len(Thread, IdLen) :-
408 write_length(Thread.id, IdLen, [quoted(true)]).
409
410thread_list([], _) --> [].
411thread_list([H|T], CW) -->
412 thread_info(H, CW),
413 ( {T == []}
414 -> []
415 ; [nl],
416 thread_list(T, CW)
417 ).
418
(Thread, CW) -->
420 { _{id:_, status:_, time:_, stacks:_} :< Thread,
421 !,
422 HrWidth is CW+18+13+13
423 },
424 [ '~|~tThread~*+ Status~tTime~18+~tStack use~13+~tallocated~13+'-[CW], nl ],
425 [ '~|~`-t~*+'-[HrWidth], nl ].
426thread_list_header(Thread, CW) -->
427 { _{id:_, status:_} :< Thread,
428 !,
429 HrWidth is CW+7
430 },
431 [ '~|~tThread~*+ Status'-[CW], nl ],
432 [ '~|~`-t~*+'-[HrWidth], nl ].
433
434thread_info(Thread, CW) -->
435 { _{id:Id, status:Status, time:Time, stacks:Stacks} :< Thread },
436 !,
437 [ '~|~t~q~*+ ~w~t~3f~18+~t~D~13+~t~D~13+'-
438 [ Id, CW, Status, Time.cpu, Stacks.total.usage, Stacks.total.allocated
439 ]
440 ].
441thread_info(Thread, CW) -->
442 { _{id:Id, status:Status} :< Thread },
443 !,
444 [ '~|~t~q~*+ ~w'-
445 [ Id, CW, Status
446 ]
447 ]