[m-rev.] diff: throw_if_near_stack_limits

Zoltan Somogyi zs at cs.mu.OZ.AU
Mon Jun 21 19:15:30 AEST 2004


library/exception.m:
	Add a new predicate, throw_if_near_stack_limits, that throws an
	exception if execution is near stack limits, after a request on
	the mercury-users mailing list.

NEWS:
	Mention the new predicate.

Zoltan.

cvs diff: Diffing .
Index: NEWS
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/NEWS,v
retrieving revision 1.334
diff -u -b -r1.334 NEWS
--- NEWS	23 May 2004 22:16:39 -0000	1.334
+++ NEWS	21 Jun 2004 08:09:06 -0000
@@ -159,6 +159,9 @@
   ensure that resources are released whether a called closure exits
   normally or throws an exception.
 
+* exception.m now contains a predicate throw_if_near_stack_limits which
+  can be used to prevent an application running out of stack space.
+
 * We've added predicates multi_map.to_flat_assoc_list/2 and
   multi_map.from_flat_assoc_list/2. 
 
cvs diff: Diffing analysis
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/doc
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing boehm_gc/tests
cvs diff: Diffing browser
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
cvs diff: Diffing compiler/notes
cvs diff: Diffing debian
cvs diff: Diffing deep_profiler
cvs diff: Diffing deep_profiler/notes
cvs diff: Diffing doc
cvs diff: Diffing extras
cvs diff: Diffing extras/aditi
cvs diff: Diffing extras/cgi
cvs diff: Diffing extras/complex_numbers
cvs diff: Diffing extras/complex_numbers/samples
cvs diff: Diffing extras/complex_numbers/tests
cvs diff: Diffing extras/concurrency
cvs diff: Diffing extras/curs
cvs diff: Diffing extras/curs/samples
cvs diff: Diffing extras/curses
cvs diff: Diffing extras/curses/sample
cvs diff: Diffing extras/dynamic_linking
cvs diff: Diffing extras/error
cvs diff: Diffing extras/graphics
cvs diff: Diffing extras/graphics/mercury_glut
cvs diff: Diffing extras/graphics/mercury_opengl
cvs diff: Diffing extras/graphics/mercury_tcltk
cvs diff: Diffing extras/graphics/samples
cvs diff: Diffing extras/graphics/samples/calc
cvs diff: Diffing extras/graphics/samples/gears
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing extras/graphics/samples/pent
cvs diff: Diffing extras/lazy_evaluation
cvs diff: Diffing extras/lex
cvs diff: Diffing extras/lex/samples
cvs diff: Diffing extras/lex/tests
cvs diff: Diffing extras/logged_output
cvs diff: Diffing extras/moose
cvs diff: Diffing extras/moose/samples
cvs diff: Diffing extras/moose/tests
cvs diff: Diffing extras/morphine
cvs diff: Diffing extras/morphine/non-regression-tests
cvs diff: Diffing extras/morphine/scripts
cvs diff: Diffing extras/morphine/source
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/posix
cvs diff: Diffing extras/quickcheck
cvs diff: Diffing extras/quickcheck/tutes
cvs diff: Diffing extras/references
cvs diff: Diffing extras/references/samples
cvs diff: Diffing extras/references/tests
cvs diff: Diffing extras/stream
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing extras/trailed_update/tests
cvs diff: Diffing extras/xml
cvs diff: Diffing extras/xml/samples
cvs diff: Diffing java
cvs diff: Diffing java/runtime
cvs diff: Diffing library
Index: library/exception.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/exception.m,v
retrieving revision 1.89
diff -u -b -r1.89 exception.m
--- library/exception.m	31 May 2004 04:13:00 -0000	1.89
+++ library/exception.m	7 Jun 2004 10:39:49 -0000
@@ -21,10 +21,9 @@
 :- interface.
 :- import_module std_util, list, io, store.
 
-%
-% throw(Exception):
-%	Throw the specified exception.
-%
+	% throw(Exception):
+	%	Throw the specified exception.
+
 :- pred throw(T).
 :- mode throw(in) is erroneous.
 
@@ -42,40 +41,44 @@
 	--->	succeeded(ground)
 	;	exception(ground).
 
-%
-% try(Goal, Result):
-%    Operational semantics:
-%	Call Goal(R).
-%	If Goal(R) fails, succeed with Result = failed.
-%	If Goal(R) succeeds, succeed with Result = succeeded(R).
-%	If Goal(R) throws an exception E, succeed with Result = exception(E).
-%    Declarative semantics:
-%       try(Goal, Result) <=>
-%               ( Goal(R), Result = succeeded(R)
-%               ; not Goal(_), Result = failed
-%               ; Result = exception(_)
-%		).
-%
+	% try(Goal, Result):
+	%
+	% Operational semantics:
+	%	Call Goal(R).
+	%	If Goal(R) fails, succeed with Result = failed.
+	%	If Goal(R) succeeds, succeed with Result = succeeded(R).
+	%	If Goal(R) throws an exception E, succeed with
+	%		Result = exception(E).
+	%
+	% Declarative semantics:
+	%       try(Goal, Result) <=>
+	%               ( Goal(R), Result = succeeded(R)
+	%               ; not Goal(_), Result = failed
+	%               ; Result = exception(_)
+	%		).
+
 :- pred try(pred(T),		    exception_result(T)).
 :- mode try(pred(out) is det,       out(cannot_fail)) is cc_multi.
 :- mode try(pred(out) is semidet,   out)              is cc_multi.
 :- mode try(pred(out) is cc_multi,  out(cannot_fail)) is cc_multi.
 :- mode try(pred(out) is cc_nondet, out)              is cc_multi.
 
-%
-% try_io(Goal, Result, IO_0, IO):
-%    Operational semantics:
-%	Call Goal(R, IO_0, IO_1).
-%	If it succeeds, succeed with Result = succeeded(R) and IO = IO_1.
-%	If it throws an exception E, succeed with Result = exception(E)
-%	and with the final IO state being whatever state resulted
-%	from the partial computation from IO_0.
-%    Declarative semantics:
-%	try_io(Goal, Result, IO_0, IO) <=>
-%		( Goal(R, IO_0, IO), Result = succeeded(R)
-%		; Result = exception(_)
-%		).
-%
+	% try_io(Goal, Result, IO_0, IO):
+	%
+	% Operational semantics:
+	%	Call Goal(R, IO_0, IO_1).
+	%	If it succeeds, succeed with Result = succeeded(R)
+	%		and IO = IO_1.
+	%	If it throws an exception E, succeed with Result = exception(E)
+	%		and with the final IO state being whatever state
+	%		resulted from the partial computation from IO_0.
+	%
+	% Declarative semantics:
+	%	try_io(Goal, Result, IO_0, IO) <=>
+	%		( Goal(R, IO_0, IO), Result = succeeded(R)
+	%		; Result = exception(_)
+	%		).
+
 :- pred try_io(pred(T, io, io),
 	exception_result(T), io, io).
 :- mode try_io(pred(out, di, uo) is det,
@@ -83,10 +86,10 @@
 :- mode try_io(pred(out, di, uo) is cc_multi,
 	out(cannot_fail), di, uo) is cc_multi.
 
-%
-% try_store(Goal, Result, Store_0, Store):
-%    Just like try_io, but for stores rather than io__states.
-%
+	% try_store(Goal, Result, Store_0, Store):
+	%
+	% Just like try_io, but for stores rather than io__states.
+
 :- pred try_store(pred(T, store(S), store(S)),
 	exception_result(T), store(S), store(S)).
 :- mode try_store(pred(out, di, uo) is det,
@@ -94,28 +97,31 @@
 :- mode try_store(pred(out, di, uo) is cc_multi,
 	out(cannot_fail), di, uo) is cc_multi.
 
-%
-% try_all(Goal, ResultList):
-%    Operational semantics:
-%	Try to find all solutions to Goal(R), using backtracking.
-%	Collect the solutions found in the ResultList, until
-%	the goal either throws an exception or fails.
-%	If it throws an exception, put that exception at the end of
-%	the ResultList.
-%    Declaratively:
-%       try_all(Goal, ResultList) <=>
-%		(if
-%			list__reverse(ResultList, [Last | AllButLast]),
-%			Last = exception(_)
-%		then
-%			all [M] (list__member(M, AllButLast) =>
-%				(M = succeeded(R), Goal(R))),
-%		else
-%			all [M] (list__member(M, ResultList) =>
-%				(M = succeeded(R), Goal(R))),
-%			all [R] (Goal(R) =>
-%				list__member(succeeded(R), ResultList)),
-%		).
+	% try_all(Goal, ResultList):
+	%
+	% Operational semantics:
+	%	Try to find all solutions to Goal(R), using backtracking.
+	%	Collect the solutions found in the ResultList, until
+	%	the goal either throws an exception or fails.
+	%	If it throws an exception, put that exception at the end of
+	%	the ResultList.
+	%
+	% Declaratively:
+	%       try_all(Goal, ResultList) <=>
+	%		(if
+	%			list__reverse(ResultList,
+	%				[Last | AllButLast]),
+	%			Last = exception(_)
+	%		then
+	%			all [M] (list__member(M, AllButLast) =>
+	%				(M = succeeded(R), Goal(R))),
+	%		else
+	%			all [M] (list__member(M, ResultList) =>
+	%				(M = succeeded(R), Goal(R))),
+	%			all [R] (Goal(R) =>
+	%				list__member(succeeded(R),
+	%					ResultList)),
+	%		).
 
 :- pred try_all(pred(T), list(exception_result(T))).
 :- mode try_all(pred(out) is det,     out(try_all_det))     is cc_multi.
@@ -129,13 +135,14 @@
 :- inst try_all_multi ---> [cannot_fail | try_all_nondet].
 :- inst try_all_nondet == list_skel(cannot_fail).
 
-%
-% incremental_try_all(Goal, AccumulatorPred, Acc0, Acc):
-%    Same as
-%	try_all(Goal, Results),
-%	std_util__unsorted_aggregate(Results, AccumulatorPred, Acc0, Acc)
-%    except that operationally, the execution of try_all
-%    and std_util__unsorted_aggregate is interleaved.
+	% incremental_try_all(Goal, AccumulatorPred, Acc0, Acc):
+	%
+	% Same as
+	%	try_all(Goal, Results),
+	%	std_util__unsorted_aggregate(Results, AccumulatorPred,
+	%		Acc0, Acc)
+	% except that operationally, the execution of try_all
+	% and std_util__unsorted_aggregate is interleaved.
 
 :- pred incremental_try_all(pred(T), pred(exception_result(T), A, A), A, A).
 :- mode incremental_try_all(pred(out) is nondet,
@@ -143,34 +150,47 @@
 :- mode incremental_try_all(pred(out) is nondet,
 	pred(in, in, out) is det, in, out) is cc_multi.
 
-%
-% rethrow(ExceptionResult):
-%	Rethrows the specified exception result
-%	(which should be of the form `exception(_)',
-%	not `succeeded(_)' or `failed'.).
-%
+	% rethrow(ExceptionResult):
+	% Rethrows the specified exception result (which should be
+	% of the form `exception(_)', not `succeeded(_)' or `failed'.).
+
 :- pred rethrow(exception_result(T)).
 :- mode rethrow(in(bound(exception(ground)))) is erroneous.
 
 :- func rethrow(exception_result(T)) = _.
 :- mode rethrow(in(bound(exception(ground)))) = out is erroneous.
 
-%
-% finally(P, PRes, Cleanup, CleanupRes, IO0, IO).
-%	Call P and ensure that Cleanup is called afterwards,
-%	no matter whether P succeeds or throws an exception.
-%	PRes is bound to the output of P.
-%	CleanupRes is bound to the output of Cleanup.
-%	A exception thrown by P will be rethrown after Cleanup
-%	is called, unless Cleanup throws an exception.
-%	This predicate performs the same function as the `finally'
-%	clause (`try {...} finally {...}') in languages such as Java.
+	% finally(P, PRes, Cleanup, CleanupRes, IO0, IO).
+	% Call P and ensure that Cleanup is called afterwards,
+	% no matter whether P succeeds or throws an exception.
+	% PRes is bound to the output of P.
+	% CleanupRes is bound to the output of Cleanup.
+	% A exception thrown by P will be rethrown after Cleanup
+	% is called, unless Cleanup throws an exception.
+	% This predicate performs the same function as the `finally'
+	% clause (`try {...} finally {...}') in languages such as Java.
+
 :- pred finally(pred(T, io, io), T, pred(io__res, io, io), io__res, io, io).
 :- mode finally(pred(out, di, uo) is det, out,
 	pred(out, di, uo) is det, out, di, uo) is det.
 :- mode finally(pred(out, di, uo) is cc_multi, out,
 	pred(out, di, uo) is cc_multi, out, di, uo) is cc_multi.
 
+	% throw_if_near_stack_limits checks if the program is near
+	% the limits of the Mercury stacks, and throws an exception
+	% (near_stack_limits) if this is the case.
+	%
+	% This predicate works only in low level C grades; in other grades,
+	% it never throws an exception.
+	%
+	% The predicate is impure instead of semipure because its effect
+	% depends not only on the execution of other impure predicates,
+	% but all calls.
+
+:- type near_stack_limits ---> near_stack_limits.
+
+:- impure pred throw_if_near_stack_limits is det.
+
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
@@ -2422,5 +2442,45 @@
 		io__nl(StdErr, !IO)
 	),
 	io__flush_output(StdErr, !IO).
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(throw_if_near_stack_limits/0).
+
+throw_if_near_stack_limits :-
+	( impure now_near_stack_limits ->
+		throw(near_stack_limits)
+	;
+		true
+	).
+
+:- impure pred now_near_stack_limits is semidet.
+:- pragma no_inline(now_near_stack_limits/0).
+
+:- pragma foreign_proc("C",
+	now_near_stack_limits,
+	[will_not_call_mercury],
+"
+#ifdef	MR_HIGHLEVEL_CODE
+	/*
+	** In high level code grades, I don't know of any portable way
+	** to check whether we are near the limits of the C stack.
+	*/
+	SUCCESS_INDICATOR = MR_FALSE;
+#else
+	int	slack = 1024;
+
+	if (((MR_maxfr + slack) < MR_CONTEXT(MR_ctxt_nondetstack_zone)->top)
+		&& ((MR_sp + slack) < MR_CONTEXT(MR_ctxt_detstack_zone)->top))
+	{
+		SUCCESS_INDICATOR = MR_FALSE;
+	} else {
+		SUCCESS_INDICATOR = MR_TRUE;
+	}
+#endif
+").
+
+now_near_stack_limits :-
+	fail.
 
 %-----------------------------------------------------------------------------%
cvs diff: Diffing profiler
cvs diff: Diffing robdd
cvs diff: Diffing runtime
cvs diff: Diffing runtime/GETOPT
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/diff
cvs diff: Diffing samples/muz
cvs diff: Diffing samples/rot13
cvs diff: Diffing samples/solutions
cvs diff: Diffing samples/tests
cvs diff: Diffing samples/tests/c_interface
cvs diff: Diffing samples/tests/c_interface/c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/tests/c_interface/mercury_calls_c
cvs diff: Diffing samples/tests/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/tests/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/tests/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/tests/diff
cvs diff: Diffing samples/tests/muz
cvs diff: Diffing samples/tests/rot13
cvs diff: Diffing samples/tests/solutions
cvs diff: Diffing samples/tests/toplevel
cvs diff: Diffing scripts
cvs diff: Diffing tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
cvs diff: Diffing tests/debugger/declarative
cvs diff: Diffing tests/dppd
cvs diff: Diffing tests/general
cvs diff: Diffing tests/general/accumulator
cvs diff: Diffing tests/general/string_format
cvs diff: Diffing tests/general/structure_reuse
cvs diff: Diffing tests/grade_subdirs
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/hard_coded/exceptions
cvs diff: Diffing tests/hard_coded/purity
cvs diff: Diffing tests/hard_coded/sub-modules
cvs diff: Diffing tests/hard_coded/typeclasses
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/invalid/purity
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/mmc_make
cvs diff: Diffing tests/mmc_make/lib
cvs diff: Diffing tests/recompilation
cvs diff: Diffing tests/tabling
cvs diff: Diffing tests/term
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: [18:09:22] waiting for juliensf's lock in /home/mercury/mercury1/repository/tests/warnings
cvs diff: [18:09:52] obtained lock in /home/mercury/mercury1/repository/tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trace
cvs diff: Diffing util
cvs diff: Diffing vim
cvs diff: Diffing vim/after
cvs diff: Diffing vim/ftplugin
cvs diff: Diffing vim/syntax
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list