first try of setup_call_cleanup/3 and setup_call_catcher_cleanup/4
This commit is contained in:
		@@ -473,6 +473,7 @@ inline static void
 | 
				
			|||||||
do_signal(yap_signals sig)
 | 
					do_signal(yap_signals sig)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  LOCK(SignalLock);
 | 
					  LOCK(SignalLock);
 | 
				
			||||||
 | 
					  if (Yap_InterruptsEnabled)
 | 
				
			||||||
    CreepFlag = Unsigned(LCL0);
 | 
					    CreepFlag = Unsigned(LCL0);
 | 
				
			||||||
  ActiveSignals |= sig;
 | 
					  ActiveSignals |= sig;
 | 
				
			||||||
  UNLOCK(SignalLock);
 | 
					  UNLOCK(SignalLock);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										39
									
								
								C/sysbits.c
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								C/sysbits.c
									
									
									
									
									
								
							@@ -1107,6 +1107,7 @@ HandleMatherr(int  sig, siginfo_t *sip, ucontext_t *uap)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if HAVE_SIGSEGV && !defined(THREADS) 
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
my_signal_info(int sig, void (*handler)(int, siginfo_t  *, ucontext_t *))
 | 
					my_signal_info(int sig, void (*handler)(int, siginfo_t  *, ucontext_t *))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -1118,6 +1119,7 @@ my_signal_info(int sig, void (*handler)(int, siginfo_t  *, ucontext_t *))
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  sigaction(sig,&sigact,NULL);
 | 
					  sigaction(sig,&sigact,NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
my_signal(int sig, void (*handler)(int, siginfo_t *, ucontext_t *))
 | 
					my_signal(int sig, void (*handler)(int, siginfo_t *, ucontext_t *))
 | 
				
			||||||
@@ -1221,6 +1223,7 @@ SearchForTrailFault(siginfo_t *siginfo)
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if HAVE_SIGSEGV && !defined(THREADS) 
 | 
				
			||||||
static RETSIGTYPE
 | 
					static RETSIGTYPE
 | 
				
			||||||
HandleSIGSEGV(int   sig, siginfo_t *siginfo, void *context)
 | 
					HandleSIGSEGV(int   sig, siginfo_t *siginfo, void *context)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -1229,6 +1232,7 @@ HandleSIGSEGV(int   sig, siginfo_t *siginfo, void *context)
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
  SearchForTrailFault(siginfo);
 | 
					  SearchForTrailFault(siginfo);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
my_signal_info(int sig, void (*handler)(int,siginfo_t *,void *))
 | 
					my_signal_info(int sig, void (*handler)(int,siginfo_t *,void *))
 | 
				
			||||||
@@ -1509,13 +1513,20 @@ HandleSIGINT (int sig, siginfo_t   *x, ucontext_t *y)
 | 
				
			|||||||
HandleSIGINT (int sig)
 | 
					HandleSIGINT (int sig)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  LOCK(SignalLock);
 | 
				
			||||||
  my_signal(SIGINT, HandleSIGINT);
 | 
					  my_signal(SIGINT, HandleSIGINT);
 | 
				
			||||||
  /* do this before we act */
 | 
					  /* do this before we act */
 | 
				
			||||||
#if HAVE_ISATTY
 | 
					#if HAVE_ISATTY
 | 
				
			||||||
  if (!isatty(0)  && !Yap_sockets_io) {
 | 
					  if (!isatty(0)  && !Yap_sockets_io) {
 | 
				
			||||||
 | 
					    UNLOCK(SignalLock);
 | 
				
			||||||
    Yap_Error(INTERRUPT_ERROR,MkIntTerm(SIGINT),NULL);
 | 
					    Yap_Error(INTERRUPT_ERROR,MkIntTerm(SIGINT),NULL);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					  if (!Yap_InterruptsEnabled) {
 | 
				
			||||||
 | 
					    UNLOCK(SignalLock);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  if (Yap_PrologMode & (CritMode|ConsoleGetcMode)) {
 | 
					  if (Yap_PrologMode & (CritMode|ConsoleGetcMode)) {
 | 
				
			||||||
    Yap_PrologMode |= InterruptMode;
 | 
					    Yap_PrologMode |= InterruptMode;
 | 
				
			||||||
#if HAVE_LIBREADLINE
 | 
					#if HAVE_LIBREADLINE
 | 
				
			||||||
@@ -1527,6 +1538,7 @@ HandleSIGINT (int sig)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					    UNLOCK(SignalLock);
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#ifdef HAVE_SETBUF
 | 
					#ifdef HAVE_SETBUF
 | 
				
			||||||
@@ -1535,9 +1547,11 @@ HandleSIGINT (int sig)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
  if (snoozing) {
 | 
					  if (snoozing) {
 | 
				
			||||||
    snoozing = FALSE;
 | 
					    snoozing = FALSE;
 | 
				
			||||||
 | 
					    UNLOCK(SignalLock);
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  ProcessSIGINT();
 | 
					  ProcessSIGINT();
 | 
				
			||||||
 | 
					  UNLOCK(SignalLock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if !defined(_WIN32)
 | 
					#if !defined(_WIN32)
 | 
				
			||||||
@@ -1619,6 +1633,8 @@ ReceiveSignal (int s)
 | 
				
			|||||||
#if (_MSC_VER || defined(__MINGW32__))
 | 
					#if (_MSC_VER || defined(__MINGW32__))
 | 
				
			||||||
static BOOL WINAPI
 | 
					static BOOL WINAPI
 | 
				
			||||||
MSCHandleSignal(DWORD dwCtrlType) {
 | 
					MSCHandleSignal(DWORD dwCtrlType) {
 | 
				
			||||||
 | 
					  if (!Yap_InterruptsEnabled) {
 | 
				
			||||||
 | 
					    return FALSE;
 | 
				
			||||||
  switch(dwCtrlType) {
 | 
					  switch(dwCtrlType) {
 | 
				
			||||||
  case CTRL_C_EVENT:
 | 
					  case CTRL_C_EVENT:
 | 
				
			||||||
  case CTRL_BREAK_EVENT:
 | 
					  case CTRL_BREAK_EVENT:
 | 
				
			||||||
@@ -2824,6 +2840,27 @@ p_win32(void)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static Int
 | 
				
			||||||
 | 
					p_enable_interrupts(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  LOCK(SignalLock);
 | 
				
			||||||
 | 
					  Yap_InterruptsEnabled = TRUE;
 | 
				
			||||||
 | 
					  UNLOCK(SignalLock);
 | 
				
			||||||
 | 
					  return TRUE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static Int
 | 
				
			||||||
 | 
					p_disable_interrupts(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  LOCK(SignalLock);
 | 
				
			||||||
 | 
					  if (ActiveSignals)
 | 
				
			||||||
 | 
					    CreepFlag = Unsigned(LCL0);
 | 
				
			||||||
 | 
					  Yap_InterruptsEnabled = FALSE;
 | 
				
			||||||
 | 
					  UNLOCK(SignalLock);
 | 
				
			||||||
 | 
					  return TRUE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static Int
 | 
					static Int
 | 
				
			||||||
p_ld_path(void)
 | 
					p_ld_path(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -3047,6 +3084,8 @@ Yap_InitSysPreds(void)
 | 
				
			|||||||
  Yap_InitCPred ("$env_separator", 1, p_env_separator, SafePredFlag);
 | 
					  Yap_InitCPred ("$env_separator", 1, p_env_separator, SafePredFlag);
 | 
				
			||||||
  Yap_InitCPred ("$unix", 0, p_unix, SafePredFlag);
 | 
					  Yap_InitCPred ("$unix", 0, p_unix, SafePredFlag);
 | 
				
			||||||
  Yap_InitCPred ("$win32", 0, p_win32, SafePredFlag);
 | 
					  Yap_InitCPred ("$win32", 0, p_win32, SafePredFlag);
 | 
				
			||||||
 | 
					  Yap_InitCPred ("$enable_interrupts", 0, p_enable_interrupts, SafePredFlag);
 | 
				
			||||||
 | 
					  Yap_InitCPred ("$disable_interrupts", 0, p_disable_interrupts, SafePredFlag);
 | 
				
			||||||
  Yap_InitCPred ("$ld_path", 1, p_ld_path, SafePredFlag);
 | 
					  Yap_InitCPred ("$ld_path", 1, p_ld_path, SafePredFlag);
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
  Yap_InitCPred ("win_registry_get_value", 3, p_win_registry_get_value,0);
 | 
					  Yap_InitCPred ("win_registry_get_value", 3, p_win_registry_get_value,0);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								H/Heap.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								H/Heap.h
									
									
									
									
									
								
							@@ -123,6 +123,7 @@ typedef struct worker_local_struct {
 | 
				
			|||||||
  union CONSULT_OBJ *consultlow;
 | 
					  union CONSULT_OBJ *consultlow;
 | 
				
			||||||
  struct pred_entry *last_asserted_pred;
 | 
					  struct pred_entry *last_asserted_pred;
 | 
				
			||||||
  int    debug_on;
 | 
					  int    debug_on;
 | 
				
			||||||
 | 
					  int    interrupts_enabled;
 | 
				
			||||||
  UInt   consultcapacity;
 | 
					  UInt   consultcapacity;
 | 
				
			||||||
  UInt   active_signals;
 | 
					  UInt   active_signals;
 | 
				
			||||||
  UInt   i_pred_arity;
 | 
					  UInt   i_pred_arity;
 | 
				
			||||||
@@ -687,6 +688,7 @@ extern struct various_codes *Yap_heap_regs;
 | 
				
			|||||||
#define  XDiff                    RINFO.x_diff
 | 
					#define  XDiff                    RINFO.x_diff
 | 
				
			||||||
#define  DelayDiff                RINFO.delay_diff
 | 
					#define  DelayDiff                RINFO.delay_diff
 | 
				
			||||||
#define  BaseDiff	          RINFO.base_diff
 | 
					#define  BaseDiff	          RINFO.base_diff
 | 
				
			||||||
 | 
					#define  Yap_InterruptsEnabled    Yap_heap_regs->WL.interrupts_enabled
 | 
				
			||||||
/* current consult stack */
 | 
					/* current consult stack */
 | 
				
			||||||
#define  ConsultSp                Yap_heap_regs->WL.consultsp
 | 
					#define  ConsultSp                Yap_heap_regs->WL.consultsp
 | 
				
			||||||
/* top of consult stack  */
 | 
					/* top of consult stack  */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										71
									
								
								docs/yap.tex
									
									
									
									
									
								
							
							
						
						
									
										71
									
								
								docs/yap.tex
									
									
									
									
									
								
							@@ -11078,7 +11078,7 @@ it will be called through call_cleanup/1.
 | 
				
			|||||||
:- fragile foo/1,bar:baz/2.
 | 
					:- fragile foo/1,bar:baz/2.
 | 
				
			||||||
@end example
 | 
					@end example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@item call_cleanup(+@var{Goal})
 | 
					@item call_cleanup(:@var{Goal})
 | 
				
			||||||
@findex call_cleanup/1
 | 
					@findex call_cleanup/1
 | 
				
			||||||
@syindex call_cleanup/1
 | 
					@syindex call_cleanup/1
 | 
				
			||||||
@cnindex call_cleanup/1
 | 
					@cnindex call_cleanup/1
 | 
				
			||||||
@@ -11087,13 +11087,80 @@ might register cleanup Goals which are called right after the end of
 | 
				
			|||||||
the call to @var{Goal}. Cuts and exceptions inside Goal do not prevent the
 | 
					the call to @var{Goal}. Cuts and exceptions inside Goal do not prevent the
 | 
				
			||||||
execution of the cleanup calls. @t{call_cleanup} might be nested.
 | 
					execution of the cleanup calls. @t{call_cleanup} might be nested.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@item call_cleanup(+@var{Goal}, +@var{CleanUpGoal})
 | 
					@item call_cleanup(:@var{Goal}, :@var{CleanUpGoal})
 | 
				
			||||||
@findex call_cleanup/2
 | 
					@findex call_cleanup/2
 | 
				
			||||||
@syindex call_cleanup/2
 | 
					@syindex call_cleanup/2
 | 
				
			||||||
@cnindex call_cleanup/2
 | 
					@cnindex call_cleanup/2
 | 
				
			||||||
This is similar to @t{call_cleanup/1} with an additional
 | 
					This is similar to @t{call_cleanup/1} with an additional
 | 
				
			||||||
@var{CleanUpGoal} which gets called after @var{Goal} is finished.
 | 
					@var{CleanUpGoal} which gets called after @var{Goal} is finished.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@item setup_call_cleanup(:@var{Setup},:@var{Goal}, :@var{CleanUpGoal})
 | 
				
			||||||
 | 
					@findex setup_call_cleanup/3
 | 
				
			||||||
 | 
					@snindex setup_call_cleanup/3
 | 
				
			||||||
 | 
					@cnindex setup_call_cleanup/3
 | 
				
			||||||
 | 
					Calls @code{(Setup, Goal)}. For each sucessful execution of @var{Setup}, calling @var{Goal}, the
 | 
				
			||||||
 | 
					cleanup handler @var{Cleanup} is guaranteed to be called exactly once.
 | 
				
			||||||
 | 
					This will happen after @var{Goal} completes, either through failure,
 | 
				
			||||||
 | 
					deterministic success, commit, or an exception.  @var{Setup} will
 | 
				
			||||||
 | 
					contain the goals that need to be protected from asynchronous interrupts
 | 
				
			||||||
 | 
					such as the ones received from @code{call_with_time_limit/2} or @code{thread_signal/2}.  In
 | 
				
			||||||
 | 
					most uses, @var{Setup} will perform temporary side-effects required by
 | 
				
			||||||
 | 
					@var{Goal} that are finally undone by \arg{Cleanup}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Success or failure of @var{Cleanup} is ignored and choice-points it
 | 
				
			||||||
 | 
					created are destroyed (as @code{once/1}). If @var{Cleanup} throws an exception,
 | 
				
			||||||
 | 
					this is executed as normal.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Typically, this predicate is used to cleanup permanent data storage
 | 
				
			||||||
 | 
					required to execute @var{Goal}, close file-descriptors, etc. The example
 | 
				
			||||||
 | 
					below provides a non-deterministic search for a term in a file, closing
 | 
				
			||||||
 | 
					the stream as needed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@example
 | 
				
			||||||
 | 
					term_in_file(Term, File) :-
 | 
				
			||||||
 | 
						setup_call_cleanup(open(File, read, In),
 | 
				
			||||||
 | 
								   term_in_stream(Term, In),
 | 
				
			||||||
 | 
								   close(In) ).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					term_in_stream(Term, In) :-
 | 
				
			||||||
 | 
						repeat,
 | 
				
			||||||
 | 
						read(In, T),
 | 
				
			||||||
 | 
						(   T == end_of_file
 | 
				
			||||||
 | 
						->  !, fail
 | 
				
			||||||
 | 
						;   T = Term
 | 
				
			||||||
 | 
						).
 | 
				
			||||||
 | 
					@end example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Note that it is impossible to implement this predicate in Prolog other than
 | 
				
			||||||
 | 
					by reading all terms into a list, close the file and call @code{member/2}.
 | 
				
			||||||
 | 
					Without @code{setup_call_cleanup/3} there is no way to gain control if the
 | 
				
			||||||
 | 
					choice-point left by code{repeat} is removed by a cut or an exception.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@code{setup_call_cleanup/2} can also be used to test determinism of a goal:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@example
 | 
				
			||||||
 | 
					?- setup_call_cleanup(true,(X=1;X=2), Det=yes).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					X = 1 ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					X = 2,
 | 
				
			||||||
 | 
					Det = yes ;
 | 
				
			||||||
 | 
					@end example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This predicate is under consideration for inclusion into the ISO standard.
 | 
				
			||||||
 | 
					For compatibility with other Prolog implementations see @code{call_cleanup/2}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 @item setup_call_cleanup(:@var{Setup},:@var{Goal}, +@var{Catcher},:@var{CleanUpGoal})
 | 
				
			||||||
 | 
					@findex setup_call_cleanup/3
 | 
				
			||||||
 | 
					@snindex setup_call_cleanup/3
 | 
				
			||||||
 | 
					@cnindex setup_call_cleanup/3
 | 
				
			||||||
 | 
					Similar to @code{setup_call_cleanup}{@var{Setup},@var{ Goal}, @var{Cleanup}} with
 | 
				
			||||||
 | 
					additional information on the reason of calling @var{Cleanup}.  Prior
 | 
				
			||||||
 | 
					to calling @var{Cleanup}, @var{Catcher} unifies with the termination
 | 
				
			||||||
 | 
					code.  If this unification fails, @var{Cleanup} is
 | 
				
			||||||
 | 
					@strong{not} called.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@item on_cleanup(+@var{CleanUpGoal})
 | 
					@item on_cleanup(+@var{CleanUpGoal})
 | 
				
			||||||
@findex on_cleanup/1
 | 
					@findex on_cleanup/1
 | 
				
			||||||
@syindex on_cleanup/1
 | 
					@syindex on_cleanup/1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -511,6 +511,8 @@ source_module(Mod) :-
 | 
				
			|||||||
	format(+,+,:),
 | 
						format(+,+,:),
 | 
				
			||||||
	call_cleanup(:,:),
 | 
						call_cleanup(:,:),
 | 
				
			||||||
	call_cleanup(:,?,:),
 | 
						call_cleanup(:,?,:),
 | 
				
			||||||
 | 
						setup_call_cleanup(:,:,:),
 | 
				
			||||||
 | 
						setup_call_catcher_cleanup(:,:,?,:),
 | 
				
			||||||
	call_residue(:,?),
 | 
						call_residue(:,?),
 | 
				
			||||||
	call_residue_vars(:,?),
 | 
						call_residue_vars(:,?),
 | 
				
			||||||
	catch(:,+,:),
 | 
						catch(:,+,:),
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										34
									
								
								pl/utils.yap
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								pl/utils.yap
									
									
									
									
									
								
							@@ -56,13 +56,37 @@ call(X,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10) :- '$execute'(X,A1,A2,A3,A4,A5,A6,A7,A8,A
 | 
				
			|||||||
call(X,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11) :- '$execute'(X,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11).
 | 
					call(X,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11) :- '$execute'(X,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
call_cleanup(Goal, Cleanup) :-
 | 
					call_cleanup(Goal, Cleanup) :-
 | 
				
			||||||
	call_cleanup(Goal, _Catcher, Cleanup).
 | 
						setup_call_cleanup(true, Goal, _Catcher, Cleanup).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
call_cleanup(Goal, Catcher, Cleanup) :-
 | 
					setup_call_cleanup(Setup, Goal, Cleanup) :-
 | 
				
			||||||
	catch('$call_cleanup'(Goal,Cleanup,Catcher),
 | 
						setup_call_catcher_cleanup(Setup, Goal, Catcher, Cleanup).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setup_call_catcher_cleanup(Setup, Goal, Catcher, Cleanup) :-
 | 
				
			||||||
 | 
						'$disable_interrupts',
 | 
				
			||||||
 | 
						'$do_setup'(Setup),
 | 
				
			||||||
 | 
						catch('$safe_call_cleanup'(Goal,Cleanup,Catcher),
 | 
				
			||||||
	      Exception,
 | 
						      Exception,
 | 
				
			||||||
	      '$cleanup_exception'(Exception,Catcher,Cleanup)).
 | 
						      '$cleanup_exception'(Exception,Catcher,Cleanup)).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					% this is simple, do nothing
 | 
				
			||||||
 | 
					'$do_setup'(A:true) :- atom(A), !.
 | 
				
			||||||
 | 
					% this is tricky: please don't forget that interrupts are disabled at this point
 | 
				
			||||||
 | 
					% and that they will only be enabled after setting up Cleanup
 | 
				
			||||||
 | 
					'$do_setup'(Setup) :-
 | 
				
			||||||
 | 
						(
 | 
				
			||||||
 | 
						 yap_hacks:current_choice_point(CP0),
 | 
				
			||||||
 | 
						 '$execute'(Setup),
 | 
				
			||||||
 | 
						 yap_hacks:current_choice_point(CP1),
 | 
				
			||||||
 | 
						 % are we looking at a deterministic goal?
 | 
				
			||||||
 | 
						 % we don't need to care about enabling interrupts
 | 
				
			||||||
 | 
						 (CP1 == CP0 -> ! ; true)
 | 
				
			||||||
 | 
						;
 | 
				
			||||||
 | 
						 % reenable interrupts if Setup failed
 | 
				
			||||||
 | 
						'$enable_interrupts',
 | 
				
			||||||
 | 
						 fail
 | 
				
			||||||
 | 
						).
 | 
				
			||||||
 | 
						 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
'$cleanup_exception'(Exception, exception(Exception), Cleanup) :- !,
 | 
					'$cleanup_exception'(Exception, exception(Exception), Cleanup) :- !,
 | 
				
			||||||
	% whatever happens, let exception go through 
 | 
						% whatever happens, let exception go through 
 | 
				
			||||||
	catch('$clean_call'(Cleanup),_,true),
 | 
						catch('$clean_call'(Cleanup),_,true),
 | 
				
			||||||
@@ -70,11 +94,13 @@ call_cleanup(Goal, Catcher, Cleanup) :-
 | 
				
			|||||||
'$cleanup_exception'(Exception, _, _) :-
 | 
					'$cleanup_exception'(Exception, _, _) :-
 | 
				
			||||||
	throw(Exception).
 | 
						throw(Exception).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
'$call_cleanup'(Goal, Cleanup, Catcher) :-
 | 
					'$safe_call_cleanup'(Goal, Cleanup, Catcher) :-
 | 
				
			||||||
 | 
						 yap_hacks:current_choice_point(MyCP1),
 | 
				
			||||||
	'$freeze_goal'(Catcher, '$clean_call'(Cleanup)),
 | 
						'$freeze_goal'(Catcher, '$clean_call'(Cleanup)),
 | 
				
			||||||
	yap_hacks:trail_suspension_marker(Catcher),
 | 
						yap_hacks:trail_suspension_marker(Catcher),
 | 
				
			||||||
	(
 | 
						(
 | 
				
			||||||
	 yap_hacks:current_choice_point(CP0),
 | 
						 yap_hacks:current_choice_point(CP0),
 | 
				
			||||||
 | 
						 '$enable_interrupts',
 | 
				
			||||||
	 '$execute'(Goal),
 | 
						 '$execute'(Goal),
 | 
				
			||||||
	 yap_hacks:current_choice_point(CPF),
 | 
						 yap_hacks:current_choice_point(CPF),
 | 
				
			||||||
	 (
 | 
						 (
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user