diff: changes to runtime startup/termination code

Fergus Henderson fjh at hydra.cs.mu.oz.au
Sat Sep 6 07:55:03 AEST 1997


Hi,

Bert, this change is based in part on your suggestions from a while back,
so could you please review this one?

--------------------

Split up the startup interface so that there are seperate
initialization and termination functions, rather than just a single
mercury_runtime_main() function which does everything.
Also change things so that the io__state data is stored in global
variables.

runtime/init.h:
util/mkinit.c:
runtime/wrapper.h:
runtime/wrapper.mod:
	Move declarations for stuff defined in wrapper.mod from init.h
	to wrapper.h.  Clean up the remainder of init.h so that it
	is clear which parts are interface and which are just there
	for use by *_init.c.

	Change the automatically-generated *_init.c files
	so that they call mercury_runtime_init(),
	mercury_runtime_main(), and mercury_runtime_terminate(),
	rather than just mercury_runtime_main().
	Define these new two functions in wrapper.mod.

	Delete the library_entry_point; change do_interpreter
	to call program_entry_point directly, rather than via
	library_entry_point.

runtime/engine.h:
runtime/engine.mod:
	Add new function terminate_engine().
	Delete the function start_mercury_engine();
	move the code that used to be there to the end
	of init_engine().

runtime/context.h:
runtime/context.mod:
	Add new function shutdown_processes(). 
	(The current implementation is just a stub.)
	Add a call to debug_memory() in init_process_context().

runtime/memory.h:
runtime/memory.c:
	Export the debug_memory() function, for use by context.c.

library/io.m:
library/io.nu.nl:
	Change things so that the io__state data is stored in C global
	variables (or, for Prolog, using assert/retract), rather than
	passing around a data structure.  (Actually we still pass the
	data structure around, but it is just a dummy Word that never
	gets used.)

	Delete the old hand-coded io__run predicate, which was
	the library entry point; instead export C functions
	ML_io_init_state() and ML_io_finalize_state().	Move the
	code for handling profiling from io__run to do_interpreter
	in runtime/wrapper.mod.

scripts/c2init.in:
	Change the default entry point from io__run_0_0 to main_2_0

cvs diff: Diffing .
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/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
cvs diff: Diffing compiler/notes
cvs diff: Diffing doc
cvs diff: Diffing extras
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/graphics
cvs diff: Diffing extras/graphics/Togl-1.2
cvs diff: Diffing extras/graphics/samples
cvs diff: Diffing extras/graphics/samples/calc
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing library
Index: library/io.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/library/io.m,v
retrieving revision 1.136
diff -u -u -r1.136 io.m
--- io.m	1997/09/01 01:01:06	1.136
+++ io.m	1997/09/05 21:30:07
@@ -925,13 +925,6 @@
 :- pred io__set_op_table(ops__table, io__state, io__state).
 :- mode io__set_op_table(di, di, uo) is det.
 
-% For use by the Mercury runtime:
-
-:- type io__external_state.
-
-:- pred io__init_state(io__external_state, io__state).
-:- mode io__init_state(di, uo) is det.
-
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
@@ -939,19 +932,25 @@
 :- import_module map, dir, term, term_io, varset, require, benchmarking, array.
 :- import_module int, std_util.
 
-:- type io__state
-	---> 	io__state(
-			io__stream_names,	% map from stream to stream name
-			io__stream_putback,	% map from input stream to
-						% list of putback characters
-						% Note: only used for the Prolog
-						% implementation.
-			ops__table, 		% current operators
-			univ,			% for use by the application
-			io__external_state
-		).
+:- type io__state == c_pointer.
+	% Values of type `io__state' are never really used:
+	% instead we store data in global variables.
+
+:- pragma c_header_code("
+	extern Word ML_io_stream_names;
+	extern Word ML_io_user_globals;
+	#if 0
+	  extern Word ML_io_ops_table;
+	#endif
+").
 
-:- type io__external_state == c_pointer.
+:- pragma c_code("
+	Word ML_io_stream_names;
+	Word ML_io_user_globals;
+	#if 0
+	  extern Word ML_io_ops_table;
+	#endif
+").
 
 :- type io__stream_names ==	map(io__stream, string).
 :- type io__stream_putback ==	map(io__stream, list(char)).
@@ -1794,54 +1793,68 @@
 
 	% XXX major design flaw with regard to unique modes
 	% means that this is very inefficient.
-io__stream_name(Stream, Name, IOState0, IOState) :-
-	IOState0 = io__state(StreamNames0, B, C, D, E),
-	copy(StreamNames0, StreamNames),
-	IOState = io__state(StreamNames, B, C, D, E),
-	( map__search(StreamNames0, Stream, Name1) ->
+io__stream_name(Stream, Name) -->
+	io__get_stream_names(StreamNames0),
+	{ map__search(StreamNames0, Stream, Name1) ->
 		Name = Name1
 	;
 		Name = "<stream name unavailable>"
-	).
+	},
+	{ copy(StreamNames0, StreamNames) }, % is this necessary?
+	io__set_stream_names(StreamNames).
+
+:- pred io__get_stream_names(io__stream_names, io__state, io__state).
+:- mode io__get_stream_names(uo, di, uo) is det.
+
+:- pragma c_code(io__get_stream_names(StreamNames::uo, IO0::di, IO::uo), "
+	StreamNames = ML_io_stream_names;
+	ML_io_stream_names = 0; /* ensure uniqueness */
+	update_io(IO0, IO);
+").
+
+:- pred io__set_stream_names(io__stream_names, io__state, io__state).
+:- mode io__set_stream_names(di, di, uo) is det.
+
+:- pragma c_code(io__set_stream_names(StreamNames::di, IO0::di, IO::uo), "
+	ML_io_stream_names = StreamNames;
+	update_io(IO0, IO);
+").
 
 :- pred io__delete_stream_name(io__stream, io__state, io__state).
 :- mode io__delete_stream_name(in, di, uo) is det.
 
-io__delete_stream_name(Stream, io__state(StreamNames0, B, C, D, E),
-		io__state(StreamNames, B, C, D, E)) :-
-	map__delete(StreamNames0, Stream, StreamNames).
+io__delete_stream_name(Stream) -->
+	io__get_stream_names(StreamNames0),
+	{ map__delete(StreamNames0, Stream, StreamNames) },
+	io__set_stream_names(StreamNames).
 
 :- pred io__insert_stream_name(io__stream, string, io__state, io__state).
 :- mode io__insert_stream_name(in, in, di, uo) is det.
 
-io__insert_stream_name(Stream, Name,
-		io__state(StreamNames0, B, C, D, E),
-		io__state(StreamNames, B, C, D, E)) :-
-	copy(Stream, Stream1),
-	copy(Name, Name1),
-	map__set(StreamNames0, Stream1, Name1, StreamNames).
+io__insert_stream_name(Stream, Name) -->
+	io__get_stream_names(StreamNames0),
+	{ copy(Stream, Stream1) },
+	{ copy(Name, Name1) },
+	{ map__set(StreamNames0, Stream1, Name1, StreamNames) },
+	io__set_stream_names(StreamNames).
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
 % global state predicates
 
-	% XXX major design flaw with regard to unique modes
-	% and io__get_globals/3
+	% XXX design flaw with regard to unique modes
+	% and io__get_globals/3: the `Globals::uo' mode here is a lie.
 
-/* old definition
-io__get_globals(Globals, IOState, IOState) :-
-	IOState = io__state(_, _, _, Globals, _).
-*/
-/* new definition - horrendously inefficient! */
-io__get_globals(Globals, IOState0, IOState) :-
-	IOState0 = io__state(A, B, C, Globals0, E),
-	copy(Globals0, Globals1),
-	IOState = io__state(A, B, C, Globals1, E),
-	Globals = Globals0.
+:- pragma c_code(io__get_globals(Globals::uo, IOState0::di, IOState::uo), "
+	Globals = ML_io_user_globals;
+	update_io(IOState0, IOState);
+").
 
-io__set_globals(Globals, io__state(A, B, C, _, E),
-		io__state(A, B, C, Globals, E)).
+:- pragma c_code(io__set_globals(Globals::di, IOState0::di, IOState::uo), "
+	ML_io_user_globals = Globals;
+	update_io(IOState0, IOState);
+").
 
 io__progname_base(DefaultName, PrognameBase) -->
 	io__progname(DefaultName, Progname),
@@ -1885,13 +1898,43 @@
 
 % miscellaneous predicates
 
-io__init_state(ExternalState, IOState) :-
-	map__init(Names0),
-	map__init(PutBack),
-	ops__init_op_table(OpTable),
-	type_to_univ("<globals>", Globals),
-	IOState0 = io__state(Names0, PutBack, OpTable, Globals, ExternalState),
-	io__insert_std_stream_names(IOState0, IOState).
+:- pred io__init_state(io__state, io__state).
+:- mode io__init_state(di, uo) is det.
+
+% for use by the Mercury runtime
+:- pragma export(io__init_state(di, uo), "ML_io_init_state").
+
+io__init_state -->
+	io__gc_init,
+	{ map__init(StreamNames) },
+	{ ops__init_op_table(OpTable) },
+	{ type_to_univ("<globals>", Globals) },
+	io__set_stream_names(StreamNames),
+	io__set_op_table(OpTable),
+	io__set_globals(Globals),
+	io__insert_std_stream_names.
+
+:- pred io__finalize_state(io__state, io__state).
+:- mode io__finalize_state(di, uo) is det.
+
+% for use by the Mercury runtime
+:- pragma export(io__finalize_state(di, uo), "ML_io_finalize_state").
+
+io__finalize_state -->
+	% currently no finalization needed...
+	% (Perhaps we should close all open Mercury files?
+	% That will happen on process exit anyway, so currently
+	% we don't bother.)
+	[].
+
+:- pred io__gc_init(io__state, io__state).
+:- mode io__gc_init(di, uo) is det.
+
+:- pragma c_code(io__gc_init(IO0::di, IO::uo), "
+	/* for Windows DLLs, we need to call GC_INIT() from each DLL */
+	GC_INIT();
+	update_io(IO0, IO);
+").
 
 :- pred io__insert_std_stream_names(io__state, io__state).
 :- mode io__insert_std_stream_names(di, uo) is det.
@@ -1919,20 +1962,13 @@
 
 %-----------------------------------------------------------------------------%
 
-	% XXX major design flaw with regard to unique modes and
+	% XXX design flaw with regard to unique modes and
 	% io__get_op_table
-/* old definition
+
 io__get_op_table(OpTable) -->
-	=(io__state(_, _, OpTable, _, _)).
-*/
-/* new definition - awfully inefficient! */
-io__get_op_table(OpTable, IOState0, IOState) :-
-	IOState0 = io__state(A, B, OpTable, D, E),
-	copy(OpTable, OpTable1),
-	IOState = io__state(A, B, OpTable1, D, E).
+	{ ops__init_op_table(OpTable) }.
 
-io__set_op_table(OpTable,	io__state(A, B, _, D, E),
-				io__state(A, B, OpTable, D, E)).
+io__set_op_table(_OpTable) --> [].
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -1971,7 +2007,7 @@
 extern MercuryFile *mercury_current_binary_input;
 extern MercuryFile *mercury_current_binary_output;
 
-#define initial_external_state()	0	/* some random number */
+#define initial_io_state()		0	/* some random number */
 #define update_io(r_src, r_dest)	((r_dest) = (r_src))
 #define final_io_state(r)		((void)0)
 
@@ -2095,88 +2131,6 @@
 		}
 		oldmem(mf);
 	}
-}
-
-").
-
-:- pragma(c_header_code, "#include ""init.h""").
-:- pragma(c_header_code, "#include ""prof.h""").
-:- pragma(c_code, "
-
-Declare_entry(mercury__io__init_state_2_0);
-
-/* This code is the program startup point -- it is called by the Mercury
-   runtime.
-
-   The handwritten code below is almost equivalent to
-
-	io__run :-
-		gc_init,
-		initial_external_state(IO0),
-		program_entry_point(IO0, IO),
-		final_io_state(IO).
-
-   except that program_entry_point is a variable, which is by default
-   set to the address of main/2.
-*/
-
-Define_extern_entry(mercury__io__run_0_0);
-Declare_label(mercury__io__run_0_0_i1);
-Declare_label(mercury__io__run_0_0_i2);
-
-BEGIN_MODULE(io_run_module)
-	init_entry(mercury__io__run_0_0);
-	init_label(mercury__io__run_0_0_i1);
-	init_label(mercury__io__run_0_0_i2);
-BEGIN_CODE
-Define_entry(mercury__io__run_0_0);
-
-#ifdef CONSERVATIVE_GC
-	GC_INIT();
-#endif
-
-        mkframe(""mercury__io__run_0_0"", 0, ENTRY(do_fail));
-	r1 = initial_external_state();
-	noprof_call(ENTRY(mercury__io__init_state_2_0),
-		LABEL(mercury__io__run_0_0_i1));
-Define_label(mercury__io__run_0_0_i1);
-#ifdef	COMPACT_ARGS
-#else
-	r1 = r2;
-#endif
-	if (program_entry_point == NULL) {
-		fatal_error(""no program entry point supplied"");
-	}
-
-#ifdef  PROFILE_TIME
-	prof_init_time_profile();
-#endif
-
-	noprof_call(program_entry_point,
-		LABEL(mercury__io__run_0_0_i2));
-
-Define_label(mercury__io__run_0_0_i2);
-
-#ifdef  PROFILE_TIME
-	prof_turn_off_time_profiling();
-	prof_output_addr_table();
-#endif
-#ifdef  PROFILE_CALLS
-	prof_output_addr_pair_table();
-#endif
-
-	final_io_state(r2);
-	succeed();
-END_MODULE
-
-/* Ensure that the initialization code for the above module gets run. */
-/*
-INIT sys_init_io_run_module
-*/
-void sys_init_io_run_module(void); /* suppress gcc -Wmissing-decl warning */
-void sys_init_io_run_module(void) {
-	extern ModuleFunc io_run_module;
-	io_run_module();
 }
 
 ").
Index: library/io.nu.nl
===================================================================
RCS file: /home/staff/zs/imp/mercury/library/io.nu.nl,v
retrieving revision 1.52
diff -u -u -r1.52 io.nu.nl
--- io.nu.nl	1997/07/28 14:57:38	1.52
+++ io.nu.nl	1997/09/05 17:09:11
@@ -1,5 +1,5 @@
 %---------------------------------------------------------------------------%
-% Copyright (C) 1994-1996 The University of Melbourne.
+% Copyright (C) 1994-1997 The University of Melbourne.
 % This file may only be copied under the terms of the GNU Library General
 % Public License - see the file COPYING.LIB in the Mercury distribution.
 %---------------------------------------------------------------------------%
@@ -35,6 +35,10 @@
 :- dynamic io__save_args/1.
 :- dynamic io__save_exit_status/1.
 
+:- dynamic io__save_user_globals/1.
+:- dynamic io__save_stream_names/1.
+:- dynamic io__save_putback/1.
+
 :- pred main(list(atom)).
 :- mode main(in) is det.
 
@@ -127,6 +131,8 @@
 	),
 	assert(io__save_exit_status(0)).
 
+:- pred io__gc_init(io__state::di, io__state::uo) is det.
+io__gc_init --> [].
 
 :- pred atoms_to_strings(list(atom), list(string)).
 :- mode atoms_to_strings(in, out) is det.
@@ -252,7 +258,7 @@
 % input predicates
 
 io__read_char_code(Stream, Code, IO_0, IO) :-
-	IO_0 = io__state(A, PutBack0, C, D, E),
+	io__save_putback(PutBack0),
  	(
 		map__search(PutBack0, Stream, PutBackChars),
 		PutBackChars = [Char | Chars]
@@ -262,22 +268,24 @@
 		;
 			map__det_update(PutBack0, Stream, Chars, PutBack)
 		),
-		IO = io__state(A, PutBack, C, D, E),
+		retractall(io__save_putback(_)),
+		assert(io__save_putback(PutBack),
 		char__to_int(Char, Code)
  	;
-		get0(Stream, Code),
-		IO = IO_0
- 	).
-	%%% io__update_state.
+		get0(Stream, Code)
+ 	),
+	IO = IO_0.
 
 io__putback_char(Stream, Char, IO_0, IO) :-
-	IO_0 = io__state(A, PutBack0, C, D, E),
+	io__save_putback(PutBack0),
 	( map__search(PutBack0, Stream, Chars) ->
 		map__det_update(PutBack0, Stream, [Char | Chars], PutBack)
 	;
 		map__det_insert(PutBack0, Stream, [Char], PutBack)
 	),
-	IO = io__state(A, PutBack, C, D, E).
+	retractall(io__save_putback(_)),
+	assert(io__save_putback(PutBack),
+	IO = IO_0.
 
 io__putback_byte(_Stream, _Char, IO, IO) :-
 	error("io__putback_byte: binary IO is not implemented for Prolog.").
@@ -454,7 +462,7 @@
 
 io__get_line_number(Stream, LineNumber) -->
 	{ lineCount(Stream, LineNumber0) },
-	=(io__state(_, PutBack, _, _, _)),
+	{ io__save_putback(PutBack) },
 	{ map__search(PutBack, Stream, Chars) ->
 		io__adjust_line_num(Chars, LineNumber0, LineNumber)
 	;
@@ -529,6 +537,18 @@
 io__set_exit_status(ExitStatus) --> 
 	{ retractall(io__save_exit_status(_)) },
 	{ assert(io__save_exit_status(ExitStatus)) }.
+
+io__get_globals(Globals) -->
+	{ io__save_user_globals(Globals) }.
+io__set_globals(Globals) -->
+	{ retractall(io__save_user_globals(_)) },
+	{ assert(io__save_user_globals(Globals) }.
+
+io__get_stream_names(StreamNames) -->
+	{ io__save_stream_names(StreamNames) }.
+io__set_stream_names(StreamNames) -->
+	{ retractall(io__save_stream_names(_)) },
+	{ assert(io__save_stream_names(StreamNames) }.
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
cvs diff: Diffing lp_solve
cvs diff: Diffing lp_solve/lp_examples
cvs diff: Diffing profiler
cvs diff: Diffing runtime
Index: runtime/context.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/context.h,v
retrieving revision 1.7
diff -u -u -r1.7 context.h
--- context.h	1997/08/23 22:34:10	1.7
+++ context.h	1997/09/05 18:13:32
@@ -170,6 +170,12 @@
 void	init_processes(void);
 
 /*
+** shutdown_processes() sends a signal to the other processes
+** to tell them to shut down.  (NOT YET IMPLEMENTED - STUB ONLY.)
+*/
+void	shutdown_processes(void);
+
+/*
 ** init_process_context() creates a top-level context for
 ** the original process, and allocates a heap and a solutions-
 ** heap for each process.
Index: runtime/context.mod
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/context.mod,v
retrieving revision 1.9
diff -u -u -r1.9 context.mod
--- context.mod	1997/08/23 22:34:11	1.9
+++ context.mod	1997/09/05 20:22:04
@@ -8,12 +8,14 @@
 
 #include "imp.h"
 
+#include <stdio.h>
 #include <unistd.h>		/* for getpid() and fork() */
 #ifdef PARALLEL
 #include <signal.h>
 #endif
 
 #include "context.h"
+#include "engine.h"	/* for `memdebug' */
 
 #ifdef	PARALLEL
 unsigned numprocs = 1;
@@ -75,9 +77,27 @@
 
 }
 
+void
+shutdown_processes(void)
+{
+#ifdef PARALLEL
+	/* XXX not yet implemented */
+	if (numprocs > 1) {
+		fprintf(stderr, "Mercury runtime: shutdown_processes()"
+			" not yet implemented\n");
+	}
+#endif
+}
+
 void 
 init_process_context(void)
 {
+	/*
+	** Each process has its own heap, in shared memory;
+	** each process may only allocate from its own heap,
+	** although it may access or modify data allocated
+	** by other processes in different heaps.
+	*/
 	init_heap();
 
 	if (my_procnum == 0) { /* the original process */
@@ -87,6 +107,8 @@
 		restore_transient_registers();
 		load_context(this_context);
 		save_transient_registers();
+
+		if (memdebug) debug_memory();
 	}
 }
 
@@ -259,7 +281,7 @@
 			** is currently runnable. If none are, then
 			** we've just floundered.
 			*/
-			is_runnable=FALSE;
+			is_runnable = FALSE;
 			for(i = 0; i < numprocs; i++)
 			{
 				if (procwaiting[i] == FALSE)
Index: runtime/engine.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/engine.h,v
retrieving revision 1.13
diff -u -u -r1.13 engine.h
--- engine.h	1997/07/27 15:08:14	1.13
+++ engine.h	1997/09/05 18:55:44
@@ -46,8 +46,8 @@
 extern	bool	debugflag[];
 
 extern	void	init_engine(void);
-extern	void	start_mercury_engine(Code *entry_point);
 extern	void	call_engine(Code *entry_point);
+extern	void	terminate_engine(void);
 extern	void	dump_prev_locations(void);
 
 Declare_entry(do_redo);
Index: runtime/engine.mod
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/engine.mod,v
retrieving revision 1.42
diff -u -u -r1.42 engine.mod
--- engine.mod	1997/07/27 15:08:16	1.42
+++ engine.mod	1997/09/05 19:47:14
@@ -33,6 +33,8 @@
 
 static jmp_buf *engine_jmp_buf;
 
+/*---------------------------------------------------------------------------*/
+
 /*
 ** init_engine() calls init_memory() which sets up all the necessary
 ** stuff for allocating memory-zones and other runtime areas (such as
@@ -41,47 +43,38 @@
 ** Next, init_engine() calls init_processes() which fork()s the right
 ** number of processes, and initializes the data structures for coordinating
 ** the interaction between multiple processes.
-** Finally, init_engine() calls init_process_context() which initializes the
+** Then, init_engine() calls init_process_context() which initializes the
 ** local context for this process including the heap and solutions heap.
 ** If it is the original process, it allocates the initial context for main.
+**
+** Finally, if there are multiple processes, init_engine calls
+** call_engine(do_runnext) for all but the first one, which makes
+** them sleep until work becomes available.  The initial process
+** returns to the caller.
 */
 void 
 init_engine(void)
 {
 	init_memory();
-	init_processes();
-	init_process_context();
 
 #ifndef USE_GCC_NONLOCAL_GOTOS
 	make_label("engine_done", LABEL(engine_done));
 #endif
-	return;
-}
-
 
-/*
-** start_mercury_engine(Code *entry_point)
-**
-** This routine is the top-level entry point into the Mercury runtime
-** engine. It should only be called once.
-**
-** It invokes call_engine(entry_point) for the first process, and if there are
-** other processes, they call call_engine(do_runnext) which makes them sleep
-** until work becomes available.
-*/
+	init_processes();
+	init_process_context();
 
-void 
-start_mercury_engine(Code *entry_point)
-{
 	if (my_procnum == 0) {
-		call_engine(entry_point);
+		return;
 	} else {
 		call_engine(ENTRY(do_runnext));
+		/* not reached */
+		MR_assert(FALSE);
 	}
-
-	return;
 }
 
+/*---------------------------------------------------------------------------*/
+
 /*
 ** call_engine(Code *entry_point)
 **
@@ -388,6 +381,21 @@
 } /* end call_engine_inner() */
 #endif /* not USE_GCC_NONLOCAL_GOTOS */
 
+/*---------------------------------------------------------------------------*/
+
+void
+terminate_engine(void)
+{
+	/*
+	** we don't bother to deallocate memory...
+	** that will happen automatically on process exit anyway.
+	*/
+
+	shutdown_processes();
+}
+
+/*---------------------------------------------------------------------------*/
+
 BEGIN_MODULE(special_labels_module)
 
 BEGIN_CODE
@@ -412,3 +420,5 @@
 #endif
 
 END_MODULE
+
+/*---------------------------------------------------------------------------*/
Index: runtime/init.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/init.h,v
retrieving revision 1.18
diff -u -u -r1.18 init.h
--- init.h	1997/08/28 18:21:16	1.18
+++ init.h	1997/09/05 19:37:24
@@ -5,8 +5,12 @@
 */
 
 /*
-** init.h - this file defines stuff used by the automatically generated
-** _init.c files.
+** init.h - this file declares stuff defined in the automatically generated
+** *_init.c files.  This is also the interface used by C code that
+** wishes to interface to Mercury.
+**
+** It also declares some stuff that is used in the automatically
+** generate *_init.c files.
 */
 
 #ifndef	INIT_H
@@ -20,12 +24,20 @@
   #include "libmer_dll.h"
 #endif
 
-#include "goto.h"		/* for Declare_entry */
-#include "mercury_types.h"	/* for `Code *' */
-#include "wrapper.h"		/* for do_init_modules() */
+/*---------------------------------------------------------------------------*/
+/*
+** This part is the interface that should be used by C programs that wish
+** to interface to Mercury.
+*/
 
 /*
 ** mercury_main() is defined in the <module>_init.c file.
+** It calls mercury_init(), mercury_call_main(), and then mercury_terminate().
+*/
+extern	int	mercury_main(int argc, char **argv);
+
+/*
+** mercury_init() is defined in the <module>_init.c file.
 **
 ** The `argc' and `argv' parameters are as for main() in C.
 ** The `stack_bottom' parameter should be the address of a variable
@@ -34,45 +46,56 @@
 ** address won't get scanned; don't store pointers to GC'ed memory
 ** in local variables that are older than that.
 **
-** mercury_main() just does some stuff to initialize the garbage
+** mercury_init() just does some stuff to initialize the garbage
 ** collector, sets some global variables, and then calls
-** mercury_runtime_main().
+** mercury_runtime_init().
 */
-extern	int		mercury_main(int argc, char **argv, char *stack_bottom);
+extern	void	mercury_init(int argc, char **argv, char *stack_bottom);
 
 /*
-** mercury_runtime_main() is defined in wrapper.mod.
-** It does some stuff to initialize the garbage collector
-** and the Mercury engine's data areas, and then calls call_engine()
-** to start execution in the library entry point.  The library
-** entry point initializes the io__state and then calls the program
-** entry point.
+** mercury_call_main() is defined in the <module>_init.c file.
+** It just calls mercury_runtime_main(), which calls main/2
+** in the Mercury program.
 */
-extern	int		mercury_runtime_main(int argc, char **argv);
+extern	void	mercury_call_main(void);
 
 /*
-** mercury_main() takes the address of the following predicates/functions.
+** mercury_terminate() is defined in the <module>_init.c file.
+** It just calls mercury_runtime_terminate(), which performs
+** any necessary cleanup, and then returns the appropriate
+** exit status as set by io__set_exit_status.
 */
-Declare_entry(mercury__main_2_0);
-Declare_entry(mercury__io__run_0_0);
-extern	void		mercury_init_io(void);
+extern	int	mercury_terminate(void);
+
+/*---------------------------------------------------------------------------*/
 
 /*
-** The following global variables are defined in wrapper.mod,
-** and set by mercury_main() on startup.
-** The entry points are set based on the options to mkinit.c.
-** The address_of_foo pointers are set to the address of
-** the corresponding foo.
+** This part defines things which are used by the automatically
+** generated *_init.c file.  These should not be used (directly)
+** by C programs that wish to interface to Mercury.
 */
-extern	Code *		library_entry_point; /* normally mercury__io__run_0_0 */
-extern	Code *		program_entry_point; /* normally mercury__main_2_0; */
 
-extern	void		(*address_of_mercury_init_io)(void);
-extern	void		(*address_of_init_modules)(void);
+#include "goto.h"		/* for Declare_entry */
+#include "mercury_types.h"	/* for `Word' */
+#include "wrapper.h"		/* for do_init_modules,
+				   mercury_runtime_init(),
+				   mercury_runtime_main(),
+				   mercury_runtime_terminate(),
+				   etc. */
 
 #ifdef CONSERVATIVE_GC
-#include "gc.h"
-extern	void		(*address_of_init_gc)(void);
+  #include "gc.h"
 #endif
 
+/*
+** mercury_main() takes the address of the following predicates/functions,
+** which are defined elsewhere.
+*/
+Declare_entry(mercury__main_2_0);		    /* in the user's program */
+extern	void	mercury_init_io(void);		    /* in the Mercury library */
+extern	void	ML_io_init_state(Word, Word *);	    /* in the Mercury library */
+extern	void	ML_io_finalize_state(Word, Word *); /* in the Mercury library */
+
 #endif /* not INIT_H */
+
+/*---------------------------------------------------------------------------*/
Index: runtime/memory.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/memory.c,v
retrieving revision 1.76
diff -u -u -r1.76 memory.c
--- memory.c	1997/08/28 18:21:25	1.76
+++ memory.c	1997/09/05 19:01:50
@@ -193,8 +193,6 @@
 static	size_t		unit;
 static	size_t		page_size;
 
-static void		debug_memory(void);
-
 static MemoryZone	*get_zone(void);
 static void		unget_zone(MemoryZone *zone);
 
@@ -287,7 +285,7 @@
 	if (memdebug) debug_memory();
 } /* end init_memory() */
 
-static void
+void
 debug_memory(void)
 {
 	MemoryZone	*zone;
Index: runtime/memory.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/memory.h,v
retrieving revision 1.27
diff -u -u -r1.27 memory.h
--- memory.h	1997/07/27 15:08:26	1.27
+++ memory.h	1997/09/05 19:02:17
@@ -194,9 +194,10 @@
 */
 ZoneHandler null_handler;
 
-/* for these two functions, see the comments in memory.c and engine.mod */
+/* for these functions, see the comments in memory.c and engine.mod */
 extern	void	init_memory(void);
 extern	void	init_heap(void);
+extern	void	debug_memory(void);
 
 /*
 ** next_offset() returns sucessive offsets across the primary cache. Useful
Index: runtime/wrapper.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/wrapper.h,v
retrieving revision 1.19
diff -u -u -r1.19 wrapper.h
--- wrapper.h	1997/08/23 22:34:12	1.19
+++ wrapper.h	1997/09/05 21:32:38
@@ -15,6 +15,43 @@
 #include <stddef.h>	/* for `size_t' */
 #include "std.h"	/* for `bool' */
 
+/*
+** mercury_runtime_init() does some stuff to initialize the garbage collector
+** and the Mercury engine's data areas, and then calls io__init_state/2
+** in the Mercury library to initialize the io__state.
+*/
+extern	void	mercury_runtime_init(int argc, char **argv);
+
+/*
+** mercury_runtime_main() basically just calls main/2,
+** with a bit of debugging scaffolding around it.
+*/
+extern	void	mercury_runtime_main(void);
+
+/*
+** mercury_runtime_terminate() does any necessary cleanup,
+** and then returns mercury_exit_status.
+*/
+extern	int	mercury_runtime_terminate(void);
+
+/*
+** The following global variables are set by mercury_init() on startup.
+** The entry points are set based on the options to mkinit.c.
+** The address_of_foo pointers are set to the address of
+** the corresponding foo.
+*/
+extern	Code *		program_entry_point; /* normally mercury__main_2_0; */
+
+extern	void		(*MR_library_initializer)(Word, Word *);
+extern	void		(*MR_library_finalizer)(Word, Word *);
+
+extern	void		(*address_of_mercury_init_io)(void);
+extern	void		(*address_of_init_modules)(void);
+
+#ifdef CONSERVATIVE_GC
+extern	void		(*address_of_init_gc)(void);
+#endif
+
 extern	void		do_init_modules(void);
 
 extern	const char *	progname;
Index: runtime/wrapper.mod
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/wrapper.mod,v
retrieving revision 1.78
diff -u -u -r1.78 wrapper.mod
--- wrapper.mod	1997/08/28 17:52:41	1.78
+++ wrapper.mod	1997/09/05 21:32:48
@@ -8,12 +8,19 @@
 ** file: wrapper.mod
 ** main authors: zs, fjh
 **
-**	This file contains the startup code for the Mercury runtime.
-**	It defines mercury_runtime_main(), which is invoked from
-**	mercury_main() in the C file generated by util/mkinit.c.
-**	The code for mercury_runtime_main() initializes various things,
-**	processes options (which are specified via an environment variable)
-**	and then invokes start_mercury_engine() to start execution.
+**	This file contains the startup and termination entry points
+**	for the Mercury runtime.
+**
+**	It defines mercury_runtime_init(), which is invoked from
+**	mercury_init() in the C file generated by util/mkinit.c.
+**	The code for mercury_runtime_init() initializes various things, and
+**	processes options (which are specified via an environment variable).
+**
+**	It also defines mercury_runtime_main(), which invokes
+**	call_engine(do_interpreter), which invokes main/2.
+**
+**	It also defines mercury_runtime_terminate(), which performs
+**	various cleanups that are needed to terminate cleanly.
 */
 
 #include	"imp.h"
@@ -73,13 +80,24 @@
 char **		mercury_argv;
 int		mercury_exit_status = 0;
 
+static Word	MR_io_state;
+
 /*
-** The Mercury runtime calls io:run/0 in the Mercury library, and the Mercury
-** library calls main/2 in the user's program.  The Mercury runtime also calls
-** init_gc() and init_modules() which are in the automatically generated
-** C init file, and mercury_init_io(), which is in the Mercury library.
+** EXTERNAL DEPENDENCIES
 **
-** But to enable Quickstart of shared libraries on Irix 5,
+** - The Mercury runtime initialization, namely mercury_runtime_init(),
+**   calls the functions init_gc() and init_modules(), which are in
+**   the automatically generated C init file; mercury_init_io(), which is
+**   in the Mercury library; and it calls the predicate io__init_state/2
+**   in the Mercury library.
+** - The Mercury runtime main, namely mercury_runtime_main(),
+**   calls main/2 in the user's program.
+** - The Mercury runtime finalization, namely mercury_runtime_terminate(),
+**   calls io__finalize_state/2 in the Mercury library.
+**
+** But, to enable Quickstart of shared libraries on Irix 5,
+** and in general to avoid various other complications
+** with shared libraries and/or Windows DLLs,
 ** we need to make sure that we don't have any undefined
 ** external references when building the shared libraries.
 ** Hence the statically linked init file saves the addresses of those
@@ -95,8 +113,12 @@
 void	(*address_of_init_gc)(void);
 #endif
 
-Code	*library_entry_point;	/* normally io:run/0 (mercury__io__run_0_0) */
-Code	*program_entry_point;	/* normally main/2 (mercury__main_2_0) */
+Code	*program_entry_point;
+		/* normally mercury__main_2_0 (main/2) */
+void	(*MR_library_initializer)(Word, Word *);
+		/* normally ML_io_init_state (io__init_state/2)*/
+void	(*MR_library_finalizer)(Word, Word *);
+		/* normally ML_io_finalize_state (io__finalize_state/2) */
 
 
 #ifdef USE_GCC_NONLOCAL_GOTOS
@@ -110,7 +132,6 @@
 static	void	process_environment_options(void);
 static	void	process_options(int argc, char **argv);
 static	void	usage(void);
-static	void	run_code(void);
 static	void	make_argv(const char *, char **, char ***, int *);
 
 #ifdef MEASURE_REGISTER_USAGE
@@ -119,8 +140,10 @@
 
 Declare_entry(do_interpreter);
 
-int 
-mercury_runtime_main(int argc, char **argv)
+/*---------------------------------------------------------------------------*/
+
+void
+mercury_runtime_init(int argc, char **argv)
 {
 #if NUM_REAL_REGS > 0
 	Word c_regs[NUM_REAL_REGS];
@@ -189,9 +212,21 @@
 
 	(*address_of_mercury_init_io)();
 
-	/* execute the selected entry point */
+	/* start up the Mercury engine */
 	init_engine();
-	run_code();
+
+	/*
+	** We need to call save_registers(), since we're about to
+	** call a C->Mercury interface function, and the C->Mercury
+	** interface convention expects them to be saved.  And before we
+	** can do that, we need to call restore_transient_registers(),
+	** since we've just returned from a C call.
+	*/
+	restore_transient_registers();
+	save_registers();
+
+	/* initialize the Mercury library */
+	(*MR_library_initializer)(MR_io_state, &MR_io_state);
 
 	/*
 	** Restore the callee-save registers before returning,
@@ -199,7 +234,6 @@
 	*/
 	restore_regs_from_mem(c_regs);
 
-	return mercury_exit_status;
 } /* end runtime_mercury_main() */
 
 void 
@@ -544,7 +578,7 @@
 				exit(1);
 			}
 
-			library_entry_point = which_label->e_addr;
+			program_entry_point = which_label->e_addr;
 
 			break;
 		}
@@ -663,11 +697,28 @@
 	exit(1);
 } /* end usage() */
 
+/*---------------------------------------------------------------------------*/
+
 void 
-run_code(void)
+mercury_runtime_main(void)
 {
+#if NUM_REAL_REGS > 0
+	Word c_regs[NUM_REAL_REGS];
+#endif
+
+#if !defined(SPEED) && defined(USE_GCC_NONLOCAL_GOTOS)
+	unsigned char	safety_buffer[SAFETY_BUFFER_SIZE];
+#endif
+
 	static	int	repcounter;
 
+	/*
+	** Save the C callee-save registers
+	** and restore the Mercury registers
+	*/
+	save_regs_to_mem(c_regs);
+	restore_registers();
+
 #if !defined(SPEED) && defined(USE_GCC_NONLOCAL_GOTOS)
 	/*
 	** double-check to make sure that we're not corrupting
@@ -676,8 +727,6 @@
 	** that it still contains only this value
 	*/
 
-	unsigned char	safety_buffer[SAFETY_BUFFER_SIZE];
-
 	global_pointer_2 = safety_buffer;	/* defeat optimization */
 	memset(safety_buffer, MAGIC_MARKER_2, SAFETY_BUFFER_SIZE);
 #endif
@@ -695,8 +744,8 @@
 
 	for (repcounter = 0; repcounter < repeats; repcounter++) {
 		debugmsg0("About to call engine\n");
-		start_mercury_engine(ENTRY(do_interpreter));
-		debugmsg0("Returning from start_mercury_engine\n");
+		call_engine(ENTRY(do_interpreter));
+		debugmsg0("Returning from call_engine()\n");
 	}
 
         if (use_own_timer) {
@@ -739,7 +788,16 @@
 		printf("%8.3fu ",
 			((double) (time_at_finish - time_at_start)) / 1000);
 	}
-} /* end run_code() */
+
+	/*
+	** Save the Mercury registers and
+	** restore the C callee-save registers before returning,
+	** since they may be used by the C code that called us.
+	*/
+	save_registers();
+	restore_regs_from_mem(c_regs);
+
+} /* end mercury_runtime_main() */
 
 #ifdef MEASURE_REGISTER_USAGE
 static void 
@@ -796,10 +854,15 @@
 	push(maxfr);
 	mkframe("interpreter", 1, LABEL(global_fail));
 
-	if (library_entry_point == NULL) {
-		fatal_error("no library entry point supplied");
+	if (program_entry_point == NULL) {
+		fatal_error("no program entry point supplied");
 	}
-	noprof_call(library_entry_point, LABEL(global_success));
+
+#ifdef  PROFILE_TIME
+	prof_init_time_profile();
+#endif
+
+	noprof_call(program_entry_point, LABEL(global_success));
 
 global_success:
 #ifndef	SPEED
@@ -828,6 +891,14 @@
 #endif
 
 all_done:
+#ifdef  PROFILE_TIME
+	prof_turn_off_time_profiling();
+	prof_output_addr_table();
+#endif
+#ifdef  PROFILE_CALLS
+	prof_output_addr_pair_table();
+#endif
+
 	maxfr = (Word *) pop();
 	succip = (Code *) pop();
 	hp = (Word *) pop();
@@ -838,9 +909,41 @@
 		printregs("after popping...");
 	}
 #endif
+
 	proceed();
 #ifndef	USE_GCC_NONLOCAL_GOTOS
 	return 0;
 #endif
 
 END_MODULE
+
+/*---------------------------------------------------------------------------*/
+
+int
+mercury_runtime_terminate(void)
+{
+#if NUM_REAL_REGS > 0
+	Word c_regs[NUM_REAL_REGS];
+#endif
+	/*
+	** Save the callee-save registers; we're going to start using them
+	** as global registers variables now, which will clobber them,
+	** and we need to preserve them, because they're callee-save,
+	** and our caller may need them.
+	*/
+	save_regs_to_mem(c_regs);
+
+	(*MR_library_finalizer)(MR_io_state, &MR_io_state);
+
+	terminate_engine();
+
+	/*
+	** Restore the callee-save registers before returning,
+	** since they may be used by the C code that called us.
+	*/
+	restore_regs_from_mem(c_regs);
+
+	return mercury_exit_status;
+}
+
+/*---------------------------------------------------------------------------*/
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/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/diff
cvs diff: Diffing scripts
Index: scripts/c2init.in
===================================================================
RCS file: /home/staff/zs/imp/mercury/scripts/c2init.in,v
retrieving revision 1.11
diff -u -u -r1.11 c2init.in
--- c2init.in	1997/07/27 15:09:29	1.11
+++ c2init.in	1997/09/05 20:44:41
@@ -22,14 +22,16 @@
 	-l, --library
 		Don't generate a \`main()' function.
 		Instead, generate a function
-			mercury_main(int argc, char **argv, char *stack_bottom);
+			mercury_main(int argc, char **argv);
 		(declared in \"init.h\") that can be called from C code.
+		(A more fine-grained interface is also available;
+		see \"init.h\" for details.)
 	-c <n>, --max-calls <n>
 		Break up the initialization into groups of at most <n> function
 		calls.  (Default value of <n> is 40.)
 	-w <label>, --entry-point <label>
 		Set entry point to <label>.
-		(Default value is \`mercury__io__run_0_0'.)
+		(Default value is \`mercury__main_2_0'.)
 Environment variables:
 	MERCURY_MOD_LIB_DIR, MERCURY_MOD_LIB_MODS, MERCURY_MKINIT.
 "
@@ -40,7 +42,7 @@
 
 # maximum number of calls to put in a single function
 maxcalls=40
-defentry=mercury__io__run_0_0
+defentry=mercury__main_2_0
 library_opt=""
 while true; do
 	case "$1" in
cvs diff: Diffing tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/general
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trial
cvs diff: Diffing util
Index: util/mkinit.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/util/mkinit.c,v
retrieving revision 1.19
diff -u -u -r1.19 mkinit.c
--- mkinit.c	1997/08/28 18:20:13	1.19
+++ mkinit.c	1997/09/05 20:39:42
@@ -37,7 +37,7 @@
 static const char *progname = NULL;
 
 /* options and arguments, set by parse_options() */
-static const char *entry_point = "mercury__io__run_0_0";
+static const char *entry_point = "mercury__io__main_2_0";
 static int maxcalls = MAXCALLS;
 static int num_files;
 static char **files;
@@ -75,7 +75,7 @@
 	"\n"
 	;
 
-static const char mercury_main_func[] =
+static const char mercury_funcs[] =
 	"\n"
 	"Declare_entry(%s);\n"
 	"\n"
@@ -96,7 +96,8 @@
 	"  #endif\n"
 	"#endif\n"
 	"\n"
-	"int mercury_main(int argc, char **argv, char *stackbottom)\n"
+	"void\n"
+	"mercury_init(int argc, char **argv, char *stackbottom)\n"
 	"{\n"
 	"\n"
 	"#ifdef CONSERVATIVE_GC\n"
@@ -128,22 +129,44 @@
 	"#ifdef CONSERVATIVE_GC\n"
 	"	address_of_init_gc = init_gc;\n"
 	"#endif\n"
+	"	MR_library_initializer = ML_io_init_state;\n"
+	"	MR_library_finalizer = ML_io_finalize_state;\n"
 	"#if defined(USE_GCC_NONLOCAL_GOTOS) && !defined(USE_ASM_LABELS)\n"
 	"	do_init_modules();\n"
 	"#endif\n"
-	"	program_entry_point = ENTRY(mercury__main_2_0);\n"
-	"	library_entry_point = ENTRY(%s);\n"
+	"	program_entry_point = ENTRY(%s);\n"
 	"\n"
-	"	return mercury_runtime_main(argc, argv);\n"
+	"	return mercury_runtime_init(argc, argv);\n"
+	"}\n"
+	"\n"
+	"void\n"
+	"mercury_call_main(void)\n"
+	"{\n"
+	"	mercury_runtime_main();\n"
+	"}\n"
+	"\n"
+	"int\n"
+	"mercury_terminate(void)\n"
+	"{\n"
+	"	return mercury_runtime_terminate();\n"
+	"}\n"
+	"\n"
+	"int\n"
+	"mercury_main(int argc, char **argv)\n"
+	"{\n"
+	"	char dummy;\n"
+	"	mercury_init(argc, argv, &dummy);\n"
+	"	mercury_call_main();\n"
+	"	return mercury_terminate();\n"
 	"}\n"
 	;
 
 static const char main_func[] =
 	"\n"
-	"int main(int argc, char **argv)\n"
+	"int\n"
+	"main(int argc, char **argv)\n"
 	"{\n"
-	"	char dummy;\n"
-	"	return mercury_main(argc, argv, &dummy);\n"
+	"	return mercury_main(argc, argv);\n"
 	"}\n"
 	;
 
@@ -317,7 +340,7 @@
 static void 
 output_main(void)
 {
-	printf(mercury_main_func, entry_point, entry_point);
+	printf(mercury_funcs, entry_point, entry_point);
 	if (output_main_func) {
 		fputs(main_func, stdout);
 	}

-- 
Fergus Henderson <fjh at cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3         |     -- the last words of T. S. Garp.



More information about the developers mailing list