1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 1999-2017, University of Amsterdam 7 VU University Amsterdam 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 17 2. Redistributions in binary form must reproduce the above copyright 18 notice, this list of conditions and the following disclaimer in 19 the documentation and/or other materials provided with the 20 distribution. 21 22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 POSSIBILITY OF SUCH DAMAGE. 34*/ 35 36:- module(thread_util, 37 [ thread_run_interactor/0, % interactor main loop 38 threads/0, % List available threads 39 join_threads/0, % Join all terminated threads 40 interactor/0, % Create a new interactor 41 interactor/1, % ?Title 42 thread_has_console/0, % True if thread has a console 43 attach_console/0, % Create a new console for thread. 44 attach_console/1, % ?Title 45 46 tspy/1, % :Spec 47 tspy/2, % :Spec, +ThreadId 48 tdebug/0, 49 tdebug/1, % +ThreadId 50 tnodebug/0, 51 tnodebug/1, % +ThreadId 52 tprofile/1 % +ThreadId 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.
74threads :- 75 threads(Threads), 76 print_message(information, threads(Threads)). 77 78threads(Threads) :- 79 findall(Thread, thread_statistics(_,Thread), Threads).
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, _).
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.
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.
138:- dynamic 139 has_console/4. % Id, In, Out, Err 140 141thread_has_console(main) :- !. % we assume main has one. 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 !.
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) :- % uses tabbed consoles 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)).
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.
xterm(1)
process opened for additional thread consoles. Each
solution must bind List to a list of atomic values. All solutions
are concatenated using append/2 to form the final argument list.
The defaults set the colors to black-on-light-yellow, enable a scrollbar, set the font using Xft font pattern and prepares the back-arrow key.
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.
xterm(1)
based
console if we use the BSD libedit based command line editor.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).
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 /******************************* 286 * DEBUGGING * 287 *******************************/
295tspy(Spec) :- 296 spy(Spec), 297 tdebug. 298 299tspy(Spec, ThreadID) :- 300 spy(Spec), 301 tdebug(ThreadID).
310tdebug :- 311 forall(debug_target(Id), thread_signal(Id, gdebug)). 312 313tdebug(ThreadID) :- 314 thread_signal(ThreadID, gdebug).
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 /******************************* 334 * REMOTE PROFILING * 335 *******************************/
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 )).
362init_pce :- 363 current_prolog_flag(gui, true), 364 !, 365 call(send(@(display), open)). % avoid autoloading 366init_pce. 367 368 369 /******************************* 370 * HOOKS * 371 *******************************/ 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 385prologmessage(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 ]. 392prologmessage(joined_threads(Threads)) --> 393 [ 'Joined the following threads'-[], nl ], 394 thread_list(Threads). 395prologmessage(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 419thread_list_header(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 ]
Interactive thread utilities
This library provides utilities that are primarily intended for interactive usage in a threaded Prolog environment. It allows for inspecting threads, manage I/O of background threads (depending on the environment) and manipulating the debug status of threads. */