300 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Prolog
		
	
	
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Prolog
		
	
	
	
	
	
| /*************************************************************************
 | |
| *									 *
 | |
| *	 YAP Prolog 							 *
 | |
| *									 *
 | |
| *	Yap Prolog was developed at NCCUP - Universidade do Porto	 *
 | |
| *									 *
 | |
| * Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997	 *
 | |
| *									 *
 | |
| **************************************************************************
 | |
| *									 *
 | |
| * File:		signals.pl						 *
 | |
| * Last rev:								 *
 | |
| * mods:									 *
 | |
| * comments:	signal handling in YAP					 *
 | |
| *									 *
 | |
| *************************************************************************/
 | |
| 
 | |
| :- meta_predicate on_signal(+,?,:), alarm(+,:,-).
 | |
| 
 | |
| '$creep'(G) :-
 | |
| 	% get the first signal from the mask
 | |
| 	'$first_signal'(Sig), !,
 | |
| 	% process it
 | |
| 	'$do_signal'(Sig, G).
 | |
| '$creep'([M|G]) :-
 | |
| 	% noise, just go on with our life.
 | |
| 	'$execute'(M:G).
 | |
| 
 | |
| '$do_signal'(sig_wake_up, G) :-
 | |
|  	'$awoken_goals'(LG),
 | |
| 	% if more signals alive, set creep flag
 | |
| 	'$continue_signals',
 | |
| 	'$wake_up_goal'(G, LG).
 | |
| % never creep on entering system mode!!!
 | |
| % don't creep on meta-call.
 | |
| '$do_signal'(sig_creep, [M|G]) :-
 | |
| 	'$creep_allowed', !,
 | |
| 	(
 | |
| 	 ( G = '$notrace'(G0) ;  G = '$oncenotrace'(G0) ; G = '$execute0'(G0,M) ; '$system_module'(M), G = G0 )
 | |
| 	->
 | |
| 	 (
 | |
| 	  '$execute_nonstop'(G0,M),
 | |
| 	  '$signal_creep'
 | |
| 	 ;
 | |
| 	  '$signal_creep',
 | |
| 	  fail
 | |
| 	 )
 | |
| 	;
 | |
| 	 '$start_creep'([M|G])
 | |
| 	).
 | |
| % 
 | |
| '$do_signal'(sig_creep, [M|G]) :-
 | |
| 	( G = '$notrace'(G0) ;  G = '$oncenotrace'(G0) ; G = '$execute0'(G0,M) ; '$system_module'(M), G = G0 ),
 | |
| 	!,
 | |
| 	(
 | |
| 	 '$execute_nonstop'(G0,M),
 | |
| 	 '$signal_creep'
 | |
| 	;
 | |
| 	 '$signal_creep',
 | |
| 	 fail
 | |
| 	).
 | |
| % 
 | |
| '$do_signal'(sig_creep, [M|G]) :-
 | |
|         '$signal_creep',
 | |
| 	'$execute_nonstop'(G,M).
 | |
| '$do_signal'(sig_delay_creep, [M|G]) :-
 | |
| 	'$execute'(M:G),
 | |
|         '$creep'.
 | |
| '$do_signal'(sig_iti, [M|G]) :-
 | |
| 	'$thread_gfetch'(Goal),
 | |
| 	% if more signals alive, set creep flag
 | |
| 	'$continue_signals',
 | |
| 	'$current_module'(M0),
 | |
| 	'$execute0'(Goal,M0),
 | |
| 	'$execute'(M:G).
 | |
| '$do_signal'(sig_trace, [M|G]) :-
 | |
| 	'$continue_signals',
 | |
| 	trace,
 | |
| 	'$execute'(M:G).
 | |
| '$do_signal'(sig_debug, [M|G]) :-
 | |
| 	'$continue_signals',
 | |
| 	debug,
 | |
| 	'$execute'(M:G).
 | |
| '$do_signal'(sig_break, [M|G]) :-
 | |
| 	'$continue_signals',
 | |
| 	break,
 | |
| 	'$execute0'(G,M).
 | |
| '$do_signal'(sig_statistics, [M|G]) :-
 | |
| 	'$continue_signals',
 | |
| 	statistics,
 | |
| 	'$execute0'(G,M).
 | |
| % the next one should never be called...
 | |
| '$do_signal'(fail, [_|_]) :-
 | |
| 	fail.
 | |
| '$do_signal'(sig_stack_dump, [M|G]) :-
 | |
| 	'$continue_signals',
 | |
| 	'$stack_dump',
 | |
| 	'$execute0'(G,M).
 | |
| % Unix signals
 | |
| '$do_signal'(sig_alarm, G) :-
 | |
| 	'$signal_handler'(sig_alarm, G).
 | |
| '$do_signal'(sig_vtalarm, G) :-
 | |
| 	'$signal_handler'(sig_vtalarm, G).
 | |
| '$do_signal'(sig_hup, G) :-
 | |
| 	'$signal_handler'(sig_hup, G).
 | |
| '$do_signal'(sig_usr1, G) :-
 | |
| 	'$signal_handler'(sig_usr1, G).
 | |
| '$do_signal'(sig_usr2, G) :-
 | |
| 	'$signal_handler'(sig_usr2, G).
 | |
| '$do_signal'(sig_pipe, G) :-
 | |
| 	'$signal_handler'(sig_pipe, G).
 | |
| 
 | |
| '$signal_handler'(Sig, [M|G]) :-
 | |
| 	'$signal_do'(Sig, Goal),
 | |
| 	% if more signals alive, set creep flag
 | |
| 	'$continue_signals',
 | |
| 	'$current_module'(M0),
 | |
| 	'$execute0'((Goal,M:G),M0).
 | |
| 
 | |
| % '$execute0' should be ignored.
 | |
| '$start_creep'([_|'$execute0'(G,M)]) :-
 | |
| 	!,
 | |
| 	'$start_creep'([M|G]).
 | |
| % '$call'() is a complicated thing
 | |
| '$start_creep'([M0|'$call'(G, CP, G0, M)]) :-
 | |
| 	!,
 | |
| 	'$creep',
 | |
| 	'$execute_nonstop'('$call'(G, CP, G0, M),M0).
 | |
| % donotrace: means do not trace! So,
 | |
| % ignore and then put creep back for the continuation.
 | |
| '$start_creep'([M0|'$notrace'(G)]) :-
 | |
| 	!,
 | |
| 	(
 | |
| 	 CP0 is '$last_choice_pt',
 | |
| 	 '$execute_nonstop'(G,M0),
 | |
| 	 CP1 is '$last_choice_pt',
 | |
| 	 % exit port: creep
 | |
| 	 '$creep',
 | |
| 	 (
 | |
| 	  % if deterministic just creep all you want.
 | |
| 	  CP0 = CP1 ->
 | |
| 	  !
 | |
| 	 ;
 | |
| 	  % extra disjunction protects reentry into usergoal
 | |
| 	  (
 | |
| 	    % cannot cut here
 | |
| 	    true
 | |
| 	   ;
 | |
| 	    % be sure to disable creep on redo port
 | |
| 	    '$disable_creep',
 | |
| 	    fail
 | |
| 	  )
 | |
| 	 )
 | |
| 	;
 | |
| 	   % put it back again on fail
 | |
| 	 '$creep',
 | |
| 	 fail	   
 | |
| 	).
 | |
| '$start_creep'([M0|'$oncenotrace'(G)]) :-
 | |
| 	!,
 | |
| 	('$execute_nonstop'(G,M0),
 | |
| 	 CP1 is '$last_choice_pt',
 | |
| 	 % exit port: creep
 | |
| 	 '$creep',
 | |
| 	 !
 | |
| 	;
 | |
| 	   % put it back again on fail
 | |
| 	 '$creep',
 | |
| 	 fail	   
 | |
| 	).
 | |
| % do not debug if we are not in debug mode. 
 | |
| '$start_creep'([Mod|G]) :-
 | |
| 	'$debug_on'(DBON), DBON = false, !,
 | |
| 	'$execute_nonstop'(G,Mod).
 | |
| '$start_creep'([Mod|G]) :-
 | |
| 	nb_getval('$system_mode',on), !,
 | |
| 	'$execute_nonstop'(G,Mod).
 | |
| % notice that the last signal to be processed must always be creep
 | |
| '$start_creep'([_|'$cut_by'(CP)]) :- !,
 | |
| 	'$$cut_by'(CP),
 | |
| 	'$creep'.
 | |
| '$start_creep'([_|true]) :- !,
 | |
| 	'$creep'.
 | |
| '$start_creep'([Mod|G]) :-
 | |
| 	'$hidden_predicate'(G,Mod), !,
 | |
| 	'$execute_nonstop'(G,Mod),
 | |
| 	'$creep'.
 | |
| % do not debug if we are zipping through.  
 | |
| '$start_creep'([Mod|G]) :-
 | |
| 	nb_getval('$debug_run',Run),
 | |
| 	Run \= off,
 | |
| 	'$zip'(-1, G, Mod), !,
 | |
|         '$signal_creep',
 | |
| 	'$execute_goal'(G, Mod).
 | |
| '$start_creep'([Mod|G]) :-
 | |
| 	CP is '$last_choice_pt',	
 | |
| 	'$do_spy'(G, Mod, CP, no).
 | |
| 
 | |
| '$execute_goal'(G, Mod) :-
 | |
| 	(
 | |
| 	 '$is_metapredicate'(G, Mod)
 | |
| 	->
 | |
| 	'$meta_call'(G,Mod)
 | |
| 	;
 | |
| 	'$execute_nonstop'(G,Mod)
 | |
| 	).
 | |
| 
 | |
| 
 | |
| '$signal_do'(Sig, Goal) :-
 | |
| 	recorded('$signal_handler', action(Sig,Goal), _), !.
 | |
| '$signal_do'(Sig, Goal) :-
 | |
| 	'$signal_def'(Sig, Goal).
 | |
| 
 | |
| % reconsult init files.
 | |
| '$signal_def'(sig_hup, (( exists('~/.yaprc') -> [-'~/.yaprc'] ; true ),
 | |
| 		      ( exists('~/.prologrc') -> [-'~/.prologrc'] ; true ),
 | |
| 		      ( exists('~/prolog.ini') -> [-'~/prolog.ini'] ; true ))).
 | |
| % die on signal default.
 | |
| '$signal_def'(sig_usr1, throw(error(signal(usr1,[]),true))).
 | |
| '$signal_def'(sig_usr2, throw(error(signal(usr2,[]),true))).
 | |
| '$signal_def'(sig_pipe, throw(error(signal(pipe,[]),true))).
 | |
| % ignore sig_alarm by default
 | |
| '$signal_def'(sig_alarm, true). 
 | |
| 
 | |
| 
 | |
| '$signal'(sig_hup).
 | |
| '$signal'(sig_usr1).
 | |
| '$signal'(sig_usr2).
 | |
| '$signal'(sig_pipe).
 | |
| '$signal'(sig_alarm).
 | |
| '$signal'(sig_vtalarm).
 | |
| 
 | |
| on_signal(Signal,OldAction,NewAction) :-
 | |
| 	var(Signal), !,
 | |
| 	(nonvar(OldAction) -> throw(error(instantiation_error,on_signal/3)) ; true),
 | |
|         '$signal'(Signal),
 | |
| 	on_signal(Signal, OldAction, NewAction).
 | |
| on_signal(Signal,OldAction,default) :-
 | |
| 	'$reset_signal'(Signal, OldAction).
 | |
| on_signal(Signal,OldAction,Action) :-
 | |
| 	var(Action), !,
 | |
| 	throw(error(system_error,'Somehow the meta_predicate declarations of on_signal are subverted!')).
 | |
| on_signal(Signal,OldAction,Action) :-
 | |
| 	Action = (_:Goal),
 | |
| 	var(Goal), !,
 | |
| 	'$check_signal'(Signal, OldAction),
 | |
| 	Goal = OldAction.
 | |
| on_signal(Signal,OldAction,Action) :-
 | |
| 	'$reset_signal'(Signal, OldAction),
 | |
|         % 13211-2 speaks only about callable
 | |
| 	( Action = M:Goal -> true ; throw(error(type_error(callable,Action),on_signal/3)) ),
 | |
| 	% the following disagrees with 13211-2:6.7.1.4 which disagrees with 13211-1:7.12.2a
 | |
| 	% but the following agrees with 13211-1:7.12.2a
 | |
| 	( nonvar(M) -> true ; throw(error(instantiation_error,on_signal/3)) ),
 | |
| 	( atom(M) -> true ; throw(error(type_error(callable,Action),on_signal/3)) ),
 | |
| 	( nonvar(Goal) -> true ; throw(error(instantiation_error,on_signal/3)) ),
 | |
| 	recordz('$signal_handler', action(Signal,Action), _).
 | |
| 
 | |
| '$reset_signal'(Signal, OldAction) :-
 | |
| 	recorded('$signal_handler', action(Signal,OldAction), Ref), !,
 | |
| 	erase(Ref).
 | |
| '$reset_signal'(_, default).
 | |
| 
 | |
| '$check_signal'(Signal, OldAction) :-
 | |
| 	recorded('$signal_handler', action(Signal,OldAction), _), !.
 | |
| '$check_signal'(_, default).
 | |
| 
 | |
| 
 | |
| alarm(Interval, Goal, Left) :-
 | |
| 	Interval == 0, !,
 | |
| 	'$alarm'(0, 0, Left0, _),
 | |
| 	on_signal(sig_alarm, _, Goal),
 | |
| 	Left = Left0.
 | |
| alarm(Interval, Goal, Left) :-
 | |
| 	integer(Interval), !,
 | |
| 	on_signal(sig_alarm, _, Goal),
 | |
| 	'$alarm'(Interval, 0, Left, _).
 | |
| alarm(Number, Goal, Left) :-
 | |
| 	float(Number), !,
 | |
| 	Secs is integer(Number),
 | |
| 	USecs is integer((Number-Secs)*1000000) mod 1000000,
 | |
| 	on_signal(sig_alarm, _, Goal),
 | |
| 	'$alarm'(Interval, 0, Left, _).
 | |
| alarm(Interval.USecs, Goal, Left.LUSecs) :-
 | |
| 	on_signal(sig_alarm, _, Goal),
 | |
| 	'$alarm'(Interval, USecs, Left, LUSecs).
 | |
| 
 | |
| raise_exception(Ball) :- throw(Ball).
 | |
| 
 | |
| on_exception(Pat, G, H) :- catch(G, Pat, H).
 | |
| 
 | |
| read_sig :-
 | |
| 	recorded('$signal_handler',X,_),
 | |
| 	writeq(X),nl,
 | |
| 	fail.
 | |
| read_sig.
 | |
| 
 | |
| 
 | |
| 
 |