for review: independent AND parallelism [runtime]

Thomas Charles CONWAY conway at cs.mu.OZ.AU
Mon Apr 27 21:28:18 AEST 1998


Hi

This post contains the changes to the runtime for adding independent AND
parallelism.

-- 
Thomas Conway    || conway at cs.mu.oz.au
AD DEUM ET VINUM || Nail here [] for new monitor.

configure.in:
	Add a test to find the number of words needed to represent a
	synchronization term.

boehm_gc/gc.h:
	fix a declaration by replacing the args () with (void).
boehm_gc/solaris_pthreads.c:
	add a missing include
	check the return values of pthread calls.

compiler/*.m:
	Add handling for the new HLDS goal type par_conj.
	Add handling for the four new LLDS instructions:
		init_sync_term
		fork
		join_and_terminate
		join_and_continue

compiler/code_info.m:
	add a new alternative for slot_contents - sync_term.

compiler/handle_options.m:
	add .par as part of the grade

compiler/hlds_goal.m:
	add the new goal type par_conj.

compiler/instmap.m:
	add instmap__unify which takes a list of instmaps
		and abstractly unifies them.
	add unify_instmap_delta which tajes two instmap deltas
		and abstractly unifies them.

compiler/llds.m:
	add the new llds instructions.

compiler/mode_info.m:
	add par_conj as a lock reason.

library/Makefile:
	work around a bug in the solaris version pthread.h

library/benchmarking.m:
	reference the stack zones from the engine structure
	rather than from global variables.

library/{nc,sp}_builtin.nl:
	add an op declaration for &.

library/std_util.m:
	change references to global variables to references inside
	the engine structure.

runtime/Mmakefile:
	add mercury_thread.{c,h}
	add THREADLIBS to the libraries

runtime/*.{c,h}
	Remove some old junk from the previous processes/shrd-mem
	changes that found their way into the repository.
	Add MR_ prefixes to lots of names.

runtime/mercury_context.c:
	Add init_thread_stuff for creating and initializing a
	context structure for the current thread.

runtime/mercury_context.h:
	add a field to the mercury context which stores the thread id
	of the thread where this context originated.
	add various macros for implementing the new llds instructions.

runtime/mercury_engine.c:
	initialize the engine structure, rather than a bunch of globals.

runtime/mercury_engine.h:
	declare the mercury_engine structure.

runtime/mercury_regorder.h:
	if MR_THREAD_SAFE, and there is at least one global register
	then use mr0 as a pointer to the mercury engine structure.

scripts/init_grade_options.sh-subr
	add thread_safe

scripts/mgnuc.in
	add THREAD_OPTS

scripts/ml.in:
	add THREAD_LIBS


cvs diff: Diffing profiler
cvs diff: Diffing runtime
Index: runtime/Mmakefile
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/Mmakefile,v
retrieving revision 1.21
diff -u -r1.21 Mmakefile
--- Mmakefile	1997/12/05 15:56:25	1.21
+++ Mmakefile	1998/03/18 23:49:45
@@ -54,6 +54,7 @@
 			mercury_string.h	\
 			mercury_table.h		\
 			mercury_tags.h		\
+			mercury_thread.h	\
 			mercury_timing.h	\
 			mercury_trace.h		\
 			mercury_trail.h		\
@@ -94,6 +95,7 @@
 			mercury_regs.c		\
 			mercury_spinlock.c	\
 			mercury_table.c		\
+			mercury_thread.c	\
 			mercury_timing.c	\
 			mercury_trace.c		\
 			mercury_trail.c 	\
@@ -110,6 +112,11 @@
 		    *.gc*)	echo "-lgc" ;;				\
 		  esac							\
 		`
+THREADLIBS	= \
+		` case "$(GRADE)" in					\
+		    *.par*) echo "-lpthread" ;;				\
+		  esac							\
+		`
 
 #-----------------------------------------------------------------------------#
 
@@ -145,7 +152,7 @@
 libmer.so: $(PIC_OBJS)
 	$(LINK_SHARED_OBJ) -o libmer.so $(PIC_OBJS)			\
 		$(SHLIB_RPATH_OPT)$(FINAL_INSTALL_MERC_GC_LIB_DIR)	\
-		$(LDFLAGS) $(LDLIBS)					\
+		$(LDFLAGS) $(LDLIBS) $(THREADLIBS)			\
 		$(SHARED_LIBS)
 
 runtime.init: $(CFILES)
Index: runtime/mercury_context.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_context.c,v
retrieving revision 1.1
diff -u -r1.1 mercury_context.c
--- mercury_context.c	1997/11/20 01:59:46	1.1
+++ mercury_context.c	1998/03/11 04:52:29
@@ -14,49 +14,62 @@
 
 #include <stdio.h>
 #include <unistd.h>		/* for getpid() and fork() */
-#ifdef PARALLEL
-#include <signal.h>
+#ifdef MR_THREAD_SAFE
+#include "mercury_thread.h"
 #endif
 
 #include "mercury_context.h"
 #include "mercury_engine.h"	/* for `memdebug' */
 
-Context	*this_context;
+Context		*MR_runqueue;
+#ifdef	MR_THREAD_SAFE
+MercuryLock	*MR_runqueue_lock;
+MercuryCond	*MR_runqueue_cond;
+#endif
+
+
 static Context	*free_context_list = NULL;
+#ifdef	MR_THREAD_SAFE
+static	MercuryLock *free_context_list_lock;
+#endif
 
-void 
-init_process_context(void)
+void
+init_thread_stuff(void)
 {
-	init_heap();
+#ifdef	MR_THREAD_SAFE
+
+	MR_runqueue_lock = make(MercuryLock);
+	pthread_mutex_init(MR_runqueue_lock, MR_MUTEX_ATTR);
 
-	this_context = new_context();
-		/* load the registers so we don't clobber hp */
-	restore_transient_registers();
-	load_context(this_context);
-	save_transient_registers();
+	MR_runqueue_cond = make(MercuryCond);
+	pthread_cond_init(MR_runqueue_cond, MR_COND_ATTR);
 
-	if (memdebug) debug_memory();
+	free_context_list_lock = make(MercuryLock);
+	pthread_mutex_init(free_context_list_lock, MR_MUTEX_ATTR);
+
+	MR_KEY_CREATE(&MR_engine_base_key, NULL);
+
+#endif
 }
 
-Context *
-new_context(void)
+void
+finalize_runqueue(void)
 {
-	Context *c;
-
-	if (free_context_list == NULL) {
-		c = (Context *) make(Context);
-		c->detstack_zone = NULL;
-		c->nondetstack_zone = NULL;
-#ifdef MR_USE_TRAIL
-		c->trail_zone = NULL;
+#ifdef	MR_THREAD_SAFE
+	pthread_mutex_destroy(MR_runqueue_lock);
+	pthread_cond_destroy(MR_runqueue_cond);
+	pthread_mutex_destroy(free_context_list_lock);
 #endif
-	} else {
-		c = free_context_list;
-		free_context_list = c->next;
-	}
+}
 
+void 
+init_context(Context *c)
+{
 	c->next = NULL;
 	c->resume = NULL;
+#ifdef	MR_THREAD_SAFE
+	c->owner_thread = (MercuryThread) NULL;
+#endif
 	c->context_succip = ENTRY(do_not_reached);
 
 	if (c->detstack_zone != NULL) {
@@ -95,15 +108,40 @@
 #endif
 
 	c->context_hp = NULL;
+}
+
+Context *
+create_context(void)
+{
+	Context *c;
+
+	MR_LOCK(free_context_list_lock, "create_context");
+	if (free_context_list == NULL) {
+		MR_UNLOCK(free_context_list_lock, "create_context i");
+		c = (Context *) make(Context);
+		c->detstack_zone = NULL;
+		c->nondetstack_zone = NULL;
+#ifdef MR_USE_TRAIL
+		c->trail_zone = NULL;
+#endif
+	} else {
+		c = free_context_list;
+		free_context_list = c->next;
+		MR_UNLOCK(free_context_list_lock, "create_context ii");
+	}
+
+	init_context(c);
 
 	return c;
 }
 
 void 
-delete_context(Context *c)
+destroy_context(Context *c)
 {
+	MR_LOCK(free_context_list_lock, "destroy_context");
 	c->next = free_context_list;
 	free_context_list = c;
+	MR_UNLOCK(free_context_list_lock, "destroy_context");
 }
 
 void 
Index: runtime/mercury_context.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_context.h,v
retrieving revision 1.3
diff -u -r1.3 mercury_context.h
--- mercury_context.h	1997/11/24 15:51:58	1.3
+++ mercury_context.h	1998/03/11 04:52:29
@@ -45,34 +45,21 @@
 
 #include "mercury_regs.h"		/* for hp. Must come before system headers. */
 
-#include <sys/types.h>		/* for pid_t */
+#include <stdio.h>
 
-#include "mercury_types.h"	/* for Word */
-#include "mercury_trail.h"	/* for MR_TrailEntry */
+#include "mercury_types.h"		/* for Word */
+#include "mercury_trail.h"		/* for MR_TrailEntry */
 #include "mercury_memory.h"		/* for MemoryZone */
-#include "mercury_spinlock.h"		/* for SpinLock */
+#include "mercury_thread.h"		/* for MercuryLock */
 #include "mercury_goto.h"		/* for GOTO() */
 
-/*
-** If we have parallelism switched on (PARALLEL is defined),
-** then we define how many processes should be used.
-** Ultimately this should be configurable through the
-** MERCURY_OPTIONS environment variable.
-*/
-#ifdef	PARALLEL
-extern unsigned numprocs;
+#ifdef	MR_THREAD_SAFE
+  #define MR_IF_THREAD_SAFE(x)	x
+#else
+  #define MR_IF_THREAD_SAFE(x)	((void) 0)
 #endif
 
 /*
-** The number of context structures initially allocated.
-** This allocation does not include the stacks that they
-** refer to - only the actual context structures.
-** At the moment if we need more than this number of contexts,
-** we just die. In the longer term, we need to allocate more.
-*/
-#define INITIAL_NUM_CONTEXTS	20
-
-/*
 ** The field names that correspond to virtual machine registers:
 ** 	sp, maxfr & curfr
 ** are prefixed with `context_' so that they don't get replaced
@@ -96,6 +83,15 @@
 		** this context is next scheduled.
 		*/
 
+#ifdef	MR_THREAD_SAFE
+	MercuryThread	owner_thread;
+		/*
+		** The owner_thread field is used to ensure that when we
+		** enter a mercury engine from C, we return to the same
+		** engine. See the coments in mercury_engine.h
+		*/
+#endif
+
 	Code		*context_succip;
 		/* succip for this context */
 
@@ -137,63 +133,48 @@
 ** need to be reinitialized, but have space allocated to
 ** them. (see comments in mercury_memory.h about reset_zone())
 */
-extern	Context **free_context_list_ptr;
+extern	Context *free_context_list;
 
 /*
 ** the runqueue is a linked list of contexts that are
 ** runnable.
 */
-extern	Context **runqueue_ptr;
-
-/*
-** this_context is a pointer to the currently executing
-** context. the fields of this_context are not necessarily
-** in sync with the real values, since *this_context only
-** gets updated when save_context() gets called.
-*/
-extern	Context *this_context;
 
-/* a pointer to a word used for the spinlock on the runqueue */
-extern	SpinLock *runqueue_lock;
+extern	Context		*MR_runqueue;
+extern	Context		*MR_suspended_forks;
+#ifdef	MR_THREAD_SAFE
+extern	MercuryLock	*MR_runqueue_lock;
+extern	MercuryCond	*MR_runqueue_cond;
+#endif
 
-/*
-** a pointer to a word used for the spinlock on the free
-** context list
-*/
-extern	SpinLock *free_context_list_lock;
 
 /*
-** init_processes() forks new process (if necessary), and
-** initializes the data-structures for managing the interactions
-** between them.
+** Initializes a context structure.
 */
-void	init_processes(void);
+void	init_context(Context *context);
 
 /*
-** shutdown_processes() sends a signal to the other processes
-** to tell them to shut down.  (NOT YET IMPLEMENTED - STUB ONLY.)
+** create_context() allocates and initializes a new context
+** structure.
 */
-void	shutdown_processes(void);
+Context	*create_context(void);
 
 /*
-** init_process_context() creates a top-level context for
-** the original process, and allocates a heap and a solutions-
-** heap for each process.
+** destroy_context(ptr) returns the context structure pointed
+** to by ptr to the free list, and releases resources as
+** necessary.
 */
-void	init_process_context(void);
+void	destroy_context(Context *context);
 
 /*
-** new_context() allocates and initializes a new context
-** structure.
+** init_thread_stuff() initializes the lock structures for the runqueue.
 */
-Context	*new_context(void);
+void	init_thread_stuff(void);
 
 /*
-** delete_context(ptr) returns the context structure pointed
-** to by ptr to the free list, and releases resources as
-** necessary.
+** finialize_runqueue() finalizes the lock structures for the runqueue.
 */
-void	delete_context(Context *context);
+void	finalize_runqueue(void);
 
 /*
 ** flounder() aborts with a runtime error message. It is called if
@@ -203,46 +184,83 @@
 void	flounder(void);
 
 /*
-** procid[N] is the process id of the Nth process.
-** procid[my_procnum] == getpid() == my_procid.
-*/
-extern	pid_t	*procid;
-
-/*
-** procwaiting[N] is true if the process procid[N] is
-** suspended because the runqueue was empty when it
-** called runnext().
-** Although we semantically want bools here, we use
-** words to ensure coherency. Since a bool may be
-** smaller than a word, storing a bool may be implemented
-** in a coherency-breaking manner.
-** (Assuming that Words can be read and written in a
-** coherent manner is sufficiently important in terms of
-** simplifying the synchronization mechanisms, that
-** we really need to do so -- or so says Tom, at least.
-** I remain unconvinced. -Fergus.)
+** schedule(Context *cptr):
 */
-typedef Word		AtomicBool;
-extern	AtomicBool	*procwaiting;
 
-/*
-** my_procnum is the number of the current process.
-** my_procnum == 0 is the original parent process.
-*/
-extern	int	my_procnum;
-extern	pid_t	my_procid;
+#ifdef	MR_THREAD_SAFE
+#define schedule(cptr)	do {					\
+		MR_LOCK(MR_runqueue_lock, "schedule");		\
+		((Context *)cptr)->next = MR_runqueue;		\
+		MR_runqueue = (Context *) (cptr);		\
+		MR_SIGNAL(MR_runqueue_cond);			\
+		MR_UNLOCK(MR_runqueue_lock, "schedule");	\
+	} while(0)
 
-/* do a context switch */
-Declare_entry(do_runnext);
-#define	runnext()	GOTO(ENTRY(do_runnext));
+	/*
+	** runnext() tries to execute the first context on the
+	** runqueue. If the context was directly called from C
+	** it may only be executed in the thread that the C call
+	** originated in or should the context return to C the
+	** C stack will be wrong!
+	** If there are no contexts that the current thread can
+	** execute, then we suspend until another thread puts something
+	** into the runqueue. Currently, it is not possible for
+	** floundering to occur, so we haven't got a check for it.
+	*/
+#define runnext()	do {					\
+		Context *rn_c, *rn_p;				\
+		unsigned x;					\
+		MercuryThread t;				\
+		x = MR_ENGINE(c_depth);				\
+		t = MR_ENGINE(owner_thread);			\
+		MR_LOCK(MR_runqueue_lock, "runnext i");		\
+		while (1) {					\
+			if (MR_exit_now == TRUE)		\
+				destroy_thread(MR_engine_base);	\
+			rn_c = MR_runqueue;			\
+			rn_p = NULL;				\
+			while (rn_c != NULL) {			\
+				if ( (x > 0 && rn_c->owner_thread == t) \
+				   ||	(rn_c->owner_thread == NULL)) \
+					break;			\
+				rn_p = rn_c;			\
+				rn_c = rn_c->next;		\
+			}					\
+			if (rn_c != NULL)			\
+				break;				\
+			MR_WAIT(MR_runqueue_cond, MR_runqueue_lock); \
+		}						\
+		MR_ENGINE(this_context) = rn_c;			\
+		if (rn_p == NULL)				\
+			MR_runqueue = rn_c->next;		\
+		else						\
+			rn_p->next = rn_c->next;		\
+		MR_UNLOCK(MR_runqueue_lock, "runnext");		\
+		load_context(MR_ENGINE(this_context));		\
+		GOTO(MR_ENGINE(this_context)->resume);		\
+	} while(0)
+#else
+#define schedule(cptr)	do {					\
+		((Context *)cptr)->next = MR_runqueue;		\
+		MR_runqueue = (Context *) (cptr);		\
+	} while(0)
 
-/*
-** schedule(Context *cptr, Code *resume):
-*/
-#define schedule(cptr, resume)	do {				\
-		fatal_error("schedule not implemented");	\
+#define runnext()	do {					\
+		if (MR_runqueue == NULL) {			\
+			fatal_error("empty runqueue");		\
+		}						\
+		MR_ENGINE(this_context) = MR_runqueue;		\
+		MR_runqueue = MR_runqueue->next;		\
+		load_context(MR_ENGINE(this_context));		\
+		GOTO(MR_ENGINE(this_context)->resume);		\
 	} while(0)
+#endif
 
+#ifdef	MR_THREAD_SAFE
+#define	IF_MR_THREAD_SAFE(x)	x
+#else
+#define IF_MR_THREAD_SAFE(x)
+#endif
 /*
 ** fork_new_context(Code *child, Code *parent, int numslots):
 ** create a new context to execute the code at `child', and
@@ -250,19 +268,26 @@
 ** The new context gets put on the runqueue, and the current
 ** context resumes at `parent'.
 */
-#define fork_new_context(child, parent, numslots) do {		\
-		Context	*fork_new_context_context;		\
-		int	fork_new_context_i;			\
-		fork_new_context_context = new_context();	\
-		for (fork_new_context_i = (numslots) ;		\
-				fork_new_context_i > 0 ;	\
-				fork_new_context_i--) {		\
-			*(fork_new_context_context->context_sp) = \
-				detstackvar(fork_new_context_i); \
-			fork_new_context_context->context_sp++;	\
-		}						\
-		fork_new_context_context->resume = (child);	\
-		schedule(fork_new_context_context, (parent));	\
+#define fork_new_context(child, parent, numslots) do {			\
+		Context	*f_n_c_context;					\
+		int	fork_new_context_i;				\
+		MR_LOCK(MR_runqueue_lock, "fork");			\
+		MR_UNLOCK(MR_runqueue_lock, "fork");			\
+		f_n_c_context = create_context();			\
+		IF_MR_THREAD_SAFE(					\
+			f_n_c_context->owner_thread = NULL;		\
+		)							\
+		for (fork_new_context_i = (numslots) ;			\
+				fork_new_context_i > 0 ;		\
+				fork_new_context_i--) {			\
+			*(f_n_c_context->context_sp) = 			\
+				detstackvar(fork_new_context_i);	\
+			f_n_c_context->context_sp++;			\
+		}							\
+		f_n_c_context->resume = (child);			\
+		schedule(f_n_c_context);				\
+		GOTO((parent));						\
+		}							\
 	} while (0)
 
 #ifndef	CONSERVATIVE_GC
@@ -331,9 +356,7 @@
 		Context	*load_context_c;				\
 		load_context_c = (cptr);				\
 		MR_succip		= load_context_c->context_succip; \
-		detstack_zone	= load_context_c->detstack_zone;	\
-		MR_sp		= load_context_c->context_sp;		\
-		nondetstack_zone = load_context_c->nondetstack_zone;	\
+		MR_sp			= load_context_c->context_sp;	\
 		MR_maxfr		= load_context_c->context_maxfr; \
 		MR_curfr		= load_context_c->context_curfr; \
 	        MR_IF_USE_TRAIL(					\
@@ -342,16 +365,18 @@
 		    MR_ticket_counter =					\
 				load_context_c->context_ticket_counter;	\
 	    	)							\
-		set_min_heap_reclamation_point(load_context_c);	\
+		MR_ENGINE(context).detstack_zone =			\
+				load_context_c->detstack_zone;		\
+		MR_ENGINE(context).nondetstack_zone =			\
+				load_context_c->nondetstack_zone;	\
+		set_min_heap_reclamation_point(load_context_c);		\
 	} while (0)
 
 #define	save_context(cptr)	do {					\
 		Context	*save_context_c;				\
 		save_context_c = (cptr);				\
 		save_context_c->context_succip	= MR_succip;		\
-		save_context_c->detstack_zone	= detstack_zone;	\
 		save_context_c->context_sp	 = MR_sp;		\
-		save_context_c->nondetstack_zone = nondetstack_zone;	\
 		save_context_c->context_maxfr	= MR_maxfr;		\
 		save_context_c->context_curfr	= MR_curfr;		\
 		MR_IF_USE_TRAIL(					\
@@ -360,35 +385,67 @@
 		    save_context_c->context_ticket_counter =		\
 						MR_ticket_counter;	\
 		)							\
+		save_context_c->detstack_zone =				\
+				MR_ENGINE(context).detstack_zone;	\
+		save_context_c->nondetstack_zone =			\
+				MR_ENGINE(context).nondetstack_zone; \
 		save_hp_in_context(save_context_c);			\
 	} while (0)
 
-/*
-** The following two macros join_and_terminate and join_and_continue
-** both take a `sync_term' which has the following structure:
-**	sync_term[SYNC_TERM_LOCK] is a SpinLock
-**	sync_term[SYNC_TERM_COUNTER] is a counter for the number of
-**			processes that need to synchronize before the
-**			parent can proceed.
-**	sync_term[SYNC_TERM_PARENT] is either NULL or a pointer to the
-**			context of the parent process. If it is non-null
-**			then the last process to arrive (the one that
-**			decrements sync_term[SYNC_TERM_COUNTER] to 0)
-**			must wake the parent.
-** These terms are allocated and manipulated as normal Mercury terms by
-** generated Mercury code.
-*/
-
-#define	SYNC_TERM_LOCK		0
-#define	SYNC_TERM_COUNTER	1
-#define	SYNC_TERM_PARENT	2
+typedef struct SYNCTERM SyncTerm;
+struct SYNCTERM {
+#ifdef	MR_THREAD_SAFE
+	MercuryLock	lock;
+#endif
+	int		count;
+	Context		*parent;
+};
+
+#ifdef	MR_THREAD_SAFE
+#define MR_init_sync_term(sync_term, nbranches)	do {			\
+		SyncTerm *st = (SyncTerm *) sync_term;			\
+		pthread_mutex_init(&(st->lock), MR_MUTEX_ATTR);		\
+		st->count = (nbranches);				\
+		st->parent = NULL;					\
+	} while (0)
+#else
+#define MR_init_sync_term(sync_term, nbranches)	do {			\
+		SyncTerm *st = (SyncTerm *) sync_term;			\
+		st->count = (nbranches);				\
+		st->parent = NULL;					\
+	} while (0)
+#endif
 
 #define join_and_terminate(sync_term)	do {				\
-		fatal_error("join_and_terminate not implemented");	\
+		SyncTerm *st = (SyncTerm *) sync_term;			\
+		MR_LOCK(&(st->lock), "terminate");			\
+		(st->count)--;						\
+		if (st->count == 0) {					\
+			assert(st->parent != NULL);			\
+			MR_UNLOCK(&(st->lock), "terminate i");		\
+			schedule(st->parent);				\
+		} else {						\
+			assert(st->count > 0);				\
+			MR_UNLOCK(&(st->lock), "terminate ii");		\
+		}							\
+		destroy_context(MR_ENGINE(this_context));		\
+		runnext();						\
 	} while (0)
 
 #define join_and_continue(sync_term, where_to)	do {			\
-		fatal_error("join_and_continue not implemented");	\
+		SyncTerm *st = (SyncTerm *) sync_term;			\
+		MR_LOCK(&(st->lock), "continue");			\
+		(st->count)--;						\
+		if (st->count == 0) {					\
+			MR_UNLOCK(&(st->lock), "continue i");		\
+			GOTO((where_to));				\
+		}							\
+		assert(st->count > 0);					\
+		save_context(MR_ENGINE(this_context));			\
+		MR_ENGINE(this_context)->resume = (where_to);		\
+		st->parent = MR_ENGINE(this_context); 			\
+		MR_UNLOCK(&(st->lock), "continue ii");			\
+		runnext();						\
 	} while (0)
 
 #endif /* not MERCURY_CONTEXT_H */
Index: runtime/mercury_engine.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_engine.c,v
retrieving revision 1.4
diff -u -r1.4 mercury_engine.c
--- mercury_engine.c	1997/12/05 17:53:51	1.4
+++ mercury_engine.c	1998/03/11 04:52:30
@@ -36,7 +36,9 @@
 
 bool	debugflag[MAXFLAG];
 
-jmp_buf *MR_engine_jmp_buf;
+#ifndef MR_THREAD_SAFE
+MercuryEngine	MR_engine_base;
+#endif
 
 /*---------------------------------------------------------------------------*/
 
@@ -48,25 +50,70 @@
 ** 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.
-** 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_engine(MercuryEngine *eng)
 {
-	init_memory();
+	/* XXX */ init_memory();
+
+#ifndef	CONSERVATIVE_GC
+	eng->heap_zone = create_zone("heap", 1, heap_size, next_offset(),
+			heap_zone_size, default_handler);
+	eng->e_hp = eng->heap_zone->min;
+
+	eng->solutions_heap_zone = create_zone("solutions_heap", 1,
+			solutions_heap_size, next_offset(),
+			solutions_heap_zone_size, default_handler);
+	eng->e_sol_hp = eng->solutions_heap_zone->min;
+
+#endif
+#ifndef SPEED
+	/*
+	** Create the dumpstack, used for debugging stack traces.
+	** Note that we can just make the dumpstack the same size as
+	** the detstack and we never have to worry about the dumpstack
+	** overflowing.
+	*/
+
+	dumpstack_zone = create_zone("dumpstack", 1, detstack_size,
+		next_offset(), detstack_zone_size, default_handler);
+#endif
+
+	eng->this_context = create_context();
 
 #ifndef USE_GCC_NONLOCAL_GOTOS
 	make_label("engine_done", LABEL(engine_done), engine_done);
 #endif
 
-	init_process_context();
+#ifdef	MR_THREAD_SAFE
+	eng->owner_thread = pthread_self();
+	eng->c_depth = 0;
+#endif
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void finalize_engine(MercuryEngine *eng)
+{
+	
+}
+
+/*---------------------------------------------------------------------------*/
+
+MercuryEngine
+*create_engine(void)
+{
+	MercuryEngine *eng;
+
+	eng = make(MercuryEngine);
+	init_engine(eng);
+	return eng;
+}
+
+void destroy_engine(MercuryEngine *eng)
+{
+	free(eng);
 }
 
 /*---------------------------------------------------------------------------*/
@@ -117,25 +164,27 @@
 	jmp_buf		* volatile prev_jmp_buf;
 
 	/*
-	** Preserve the value of MR_engine_jmp_buf on the C stack.
+	** Preserve the value of MR_ENGINE(e_jmp_buf) on the C stack.
 	** This is so "C calls Mercury which calls C which calls Mercury" etc.
 	** will work.
 	*/
 
-	prev_jmp_buf = MR_engine_jmp_buf;
-	MR_engine_jmp_buf = &curr_jmp_buf;
+	restore_transient_registers();
+
+	prev_jmp_buf = MR_ENGINE(e_jmp_buf);
+	MR_ENGINE(e_jmp_buf) = &curr_jmp_buf;
 
 	/*
 	** Mark this as the spot to return to.
 	** On return, restore the registers (since longjmp may clobber
-	** them), restore the saved value of MR_engine_jmp_buf, and then
+	** them), restore the saved value of MR_ENGINE(e_jmp_buf), and then
 	** exit.
 	*/
 
 	if (setjmp(curr_jmp_buf)) {
 		debugmsg0("...caught longjmp\n");
 		restore_registers();
-		MR_engine_jmp_buf = prev_jmp_buf;
+		MR_ENGINE(e_jmp_buf) = prev_jmp_buf;
 		return;
 	}
 
@@ -149,6 +198,9 @@
 void 
 call_engine_inner(Code *entry_point)
 {
+#ifdef	MR_THREAD_SAFE
+	MercuryThread saved_owner_thread;
+#endif
 	/*
 	** Allocate some space for local variables in other
 	** procedures. This is done because we may jump into the middle
@@ -203,6 +255,17 @@
 	debugmsg1("in `call_engine', locals at %p\n", (void *)locals);
 
 	/*
+	** Increment the number of times we've entered this
+	** engine from C, and mark the current context as being
+	** owned by this thread.
+	*/
+#ifdef	MR_THREAD_SAFE
+	MR_ENGINE(c_depth)++;
+	saved_owner_thread = MR_ENGINE(this_context)->owner_thread;
+	MR_ENGINE(this_context)->owner_thread = MR_ENGINE(owner_thread);
+#endif
+
+	/*
 	** Now just call the entry point
 	*/
 
@@ -210,6 +273,18 @@
 
 Define_label(engine_done);
 	/*
+	** Decrement the number of times we've entered this
+	** engine from C and restore the owning thread in
+	** the current context.
+	*/
+#ifdef	MR_THREAD_SAFE
+	assert(MR_ENGINE(this_context)->owner_thread
+		== MR_ENGINE(owner_thread));
+	MR_ENGINE(c_depth)--;
+	MR_ENGINE(this_context)->owner_thread = saved_owner_thread;
+#endif
+
+	/*
 	** We need to ensure that there is at least one
 	** real function call in call_engine(), because
 	** otherwise gcc thinks that it doesn't need to
@@ -262,7 +337,7 @@
 	*/
 	save_registers();
 	debugmsg0("longjmping out...\n");
-	longjmp(*MR_engine_jmp_buf, 1);
+	longjmp(*(MR_ENGINE(e_jmp_buf)), 1);
 }} /* end call_engine_inner() */
 
 /* with nonlocal gotos, we don't save the previous locations */
@@ -291,7 +366,7 @@
 {
 	save_registers();
 	debugmsg0("longjmping out...\n");
-	longjmp(*MR_engine_jmp_buf, 1);
+	longjmp(*(MR_ENGINE(e_jmp_buf), 1);
 }
 
 static Code *
Index: runtime/mercury_engine.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_engine.h,v
retrieving revision 1.2
diff -u -r1.2 mercury_engine.h
--- mercury_engine.h	1997/11/23 07:21:21	1.2
+++ mercury_engine.h	1998/03/18 04:05:11
@@ -15,10 +15,12 @@
 
 #include <setjmp.h>
 
+#include "mercury_regs.h"		/* for NUM_REAL_REGS */
 #include "mercury_std.h"		/* for `bool' */
 #include "mercury_types.h"		/* for `Code *' */
 #include "mercury_goto.h"		/* for `Define_entry()' */
-#include "mercury_regs.h"		/* for NUM_REAL_REGS */
+#include "mercury_thread.h"		/* for pthread types */
+#include "mercury_context.h"		/* for MR_IF_USE_TRAIL */
 
 #define	PROGFLAG	0
 #define	GOTOFLAG	1
@@ -57,7 +59,7 @@
 
 typedef struct {
 		jmp_buf *mercury_env;	/* 
-					** used to save MR_engine_jmp_buf 
+					** used to save MR_ENGINE(e_jmp_buf )
 					*/
 		jmp_buf env;		/* 
 					** used by calls to setjmp and longjmp 
@@ -78,7 +80,7 @@
 	/*
 	** MR_setjmp(MR_jmp_buf *env, longjmp_label)
 	**
-	** Save MR_engine_jmp_buf, save the Mercury state, call setjmp(env), 
+	** Save MR_ENGINE(e_jmp_buf), save the Mercury state, call setjmp(env), 
 	** then fall through.
 	**
 	** When setjmp returns via a call to longjmp, control will pass to
@@ -94,9 +96,9 @@
 	*/
 #define MR_setjmp(setjmp_env, longjmp_label)				\
 	    do {							\
-		(setjmp_env)->mercury_env = MR_engine_jmp_buf;		\
+		(setjmp_env)->mercury_env = MR_ENGINE(e_jmp_buf);	\
 		save_regs_to_mem((setjmp_env)->regs);			\
-		(setjmp_env)->saved_succip = succip;			\
+		(setjmp_env)->saved_succip = MR_succip;			\
 		(setjmp_env)->saved_sp = sp;				\
 		(setjmp_env)->saved_curfr = curfr;			\
 		(setjmp_env)->saved_maxfr = maxfr;			\
@@ -105,9 +107,9 @@
 		MR_IF_USE_TRAIL((setjmp_env)->saved_ticket_counter =	\
 				MR_ticket_counter);			\
 		if (setjmp((setjmp_env)->env)) {			\
-			MR_engine_jmp_buf = (setjmp_env)->mercury_env;	\
+			MR_ENGINE(e_jmp_buf) = (setjmp_env)->mercury_env; \
 			restore_regs_from_mem((setjmp_env)->regs);	\
-			succip = (setjmp_env)->saved_succip;		\
+			MR_succip = (setjmp_env)->saved_succip;		\
 			sp = (setjmp_env)->saved_sp;			\
 			curfr = (setjmp_env)->saved_curfr;		\
 			maxfr = (setjmp_env)->saved_maxfr;		\
@@ -126,15 +128,131 @@
 	*/
 #define MR_longjmp(setjmp_env)	longjmp((setjmp_env)->env, 1)
 
-	/* 
-	** engine_jmp_buf should only be referred to in engine.c
-	** and the MR_setjmp and MR_longjmp macros defined above.
+extern	bool	debugflag[];
+
+typedef struct MR_MERCURY_ENGINE {
+	Word		fake_reg[MAX_FAKE_REG];
+		/* The fake reg vector for this engine. */
+#ifndef CONSERVATIVE_GC
+	Word		*e_hp;
+		/* The heap pointer for this engine */
+	Word		*e_sol_hp;
+		/* The solutions heap pointer for this engine */
+#endif
+	Context		*this_context;
+		/*
+		** this_context points to the context currently
+		** executing in this engine.
+		*/
+	Context		context;
+		/*
+		** context stores all the context information
+		** for the context executing in this engine.
+		*/
+#ifdef	MR_THREAD_SAFE
+	MercuryThread	owner_thread;
+	unsigned	c_depth;
+		/*
+		** These two fields are used to ensure that when a
+		** thread executing C code calls the Mercury engine
+		** associated with that thread, the Mercury code
+		** will finish in the same engine and return appropriately.
+		** Each time C calls Mercury in a thread, the c_depth
+		** is incremented, and the owner_thread field of the current
+		** context is set to the id of the thread. While the
+		** owner_thread is set, the context will not be scheduled
+		** for execution by any other thread. When the call to
+		** the Mercury engine finishes, c_depth is decremented and
+		** the owner_thread field of the current context is restored
+		** to its previous value.
+		*/
+#endif
+	jmp_buf		*e_jmp_buf;
+#ifndef	CONSERVATIVE_GC
+	MemoryZone	*heap_zone;
+	MemoryZone	*solutions_heap_zone;
+#endif
+#ifndef	SPEED
+	MemoryZone	*dumpstack_zone;
+	int		dumpindex;
+#endif
+} MercuryEngine;
+
+/*
+** MR_engine_base refers to the engine in which execution is taking place.
+** In the non-thread-safe situation, it is just a global variable.
+** In the thread-safe situation, MR_engine_base is either a global
+** register (if one is available), or a macro that accesses thread-local
+** storage.
+*/
+
+#ifdef	MR_THREAD_SAFE
+
+  extern MercuryThreadKey	MR_engine_base_key;
+
+  #define MR_thread_engine_base ((MercuryEngine *) \
+  			MR_GETSPECIFIC(MR_engine_base_key))
+
+  #if NUM_REAL_REGS > 0
+    #define	MR_ENGINE_BASE_REGISTER
+  	/*
+	** MR_engine_base is defined in machdeps/{arch}.h
 	*/
-extern	jmp_buf *MR_engine_jmp_buf;
+  #else
+	#define	MR_engine_base	MR_thread_engine_base
+  #endif
 
-extern	bool	debugflag[];
+  #define MR_ENGINE(x)		(((MercuryEngine *)MR_engine_base)->x)
+  #define MR_get_engine()	MR_thread_engine_base
+
+  #ifndef	CONSERVATIVE_GC
+  #define IF_NOT_CONSERVATIVE_GC(x)	x
+  #else
+  #define IF_NOT_CONSERVATIVE_GC(x)
+  #endif
+
+  #define load_engine_regs(eng)	do {					\
+		IF_NOT_CONSERVATIVE_GC(MR_hp = (eng)->e_hp;)		\
+		IF_NOT_CONSERVATIVE_GC(MR_sol_hp = (eng)->e_sol_hp;)	\
+	} while (0)
+
+  #define save_engine_regs(eng)	do {					\
+		IF_NOT_CONSERVATIVE_GC((eng)->e_hp = MR_hp;)		\
+		IF_NOT_CONSERVATIVE_GC((eng)->e_sol_hp = MR_sol_hp;)	\
+	} while (0)
+
+#else 	/* !MR_THREAD_SAFE */
+
+  extern MercuryEngine	MR_engine_base;
+  #define MR_ENGINE(x)		(MR_engine_base.x)
+  #define MR_get_engine()	(&MR_engine_base)
+
+  #ifndef	CONSERVATIVE_GC
+  #define IF_NOT_CONSERVATIVE_GC(x)	x
+  #else
+  #define IF_NOT_CONSERVATIVE_GC(x)
+  #endif
+
+  #define load_engine_regs(eng)	do {					\
+		IF_NOT_CONSERVATIVE_GC(MR_hp = (eng)->e_hp;)		\
+		IF_NOT_CONSERVATIVE_GC(MR_sol_hp = (eng)->e_sol_hp;)	\
+	} while (0)
+
+  #define save_engine_regs(eng)	do {					\
+		IF_NOT_CONSERVATIVE_GC((eng)->e_hp = MR_hp;)		\
+		IF_NOT_CONSERVATIVE_GC((eng)->e_sol_hp = MR_sol_hp;)	\
+	} while (0)
+
+
+#endif	/* !MR_THREAD_SAFE */
+
+
+extern	MercuryEngine	*create_engine(void);
+extern	void		destroy_engine(MercuryEngine *engine);
+
+extern	void	init_engine(MercuryEngine *engine);
+extern	void	finalize_engine(MercuryEngine *engine);
 
-extern	void	init_engine(void);
 extern	void	call_engine(Code *entry_point);
 extern	void	terminate_engine(void);
 extern	void	dump_prev_locations(void);
Index: runtime/mercury_heap.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_heap.h,v
retrieving revision 1.4
diff -u -r1.4 mercury_heap.h
--- mercury_heap.h	1997/12/10 02:07:35	1.4
+++ mercury_heap.h	1998/03/11 04:52:30
@@ -95,33 +95,33 @@
   #define tag_incr_hp_atomic(dest, tag, count) \
 	tag_incr_hp((dest), (tag), (count))
 
-  #define mark_hp(dest)						\
-	(							\
-		(dest) = (Word) MR_hp,				\
-		(void)0						\
-	)
+  #define mark_hp(dest)		((dest) = (Word) MR_hp)
 
   /*
   ** When restoring hp, we must make sure that we don't truncate the heap
   ** further than it is safe to. We can only truncate it as far as
-  ** min_heap_reclamation_point. See the comments in mercury_context.h next
-  ** to the set_min_heap_reclamation_point() macro.
+  ** min_heap_reclamation_point. See the comments in mercury_context.h next to
+  ** the set_min_heap_reclamation_point() macro.
   */
-  #define restore_hp(src)					\
-	(							\
-		LVALUE_CAST(Word, MR_hp) =			\
-			  ( 	(Word) MR_min_hp_rec < (src)	\
-			  ?	(src)				\
-			  :	(Word) MR_min_hp_rec		\
-			  ),					\
-		(void)0						\
-	)
+  #define	restore_hp(src)	(					\
+  			LVALUE_CAST(Word,MR_hp) = (src),		\
+  			(void)0						\
+  		)
 
-  #define hp_alloc(count)  incr_hp(hp, count)
+  /*
+  #define	restore_hp(src)	(					\
+  			LVALUE_CAST(Word,MR_hp) =			\
+  			  ( (Word) MR_min_hp_rec < (src) ?		\
+  			  (src) : (Word) MR_min_hp_rec ),		\
+  			(void)0						\
+  		)
+  */
+  
+  #define hp_alloc(count)  incr_hp(hp,count)
   #define hp_alloc_atomic(count) incr_hp_atomic(count)
-
-#endif /* not CONSERVATIVE_GC */
-
+  
+  #endif /* not CONSERVATIVE_GC */
+  
 #ifdef	PROFILE_MEMORY
   #define tag_incr_hp_msg(dest, tag, count, proclabel, type)		\
 	(								\
Index: runtime/mercury_imp.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_imp.h,v
retrieving revision 1.4
diff -u -r1.4 mercury_imp.h
--- mercury_imp.h	1997/12/05 15:56:38	1.4
+++ mercury_imp.h	1998/03/11 04:52:31
@@ -55,7 +55,9 @@
 
 #include	"mercury_label.h"
 #include	"mercury_wrapper.h"
+#include	"mercury_engine.h"
 #include	"mercury_context.h"
+#include	"mercury_thread.h"
 #include	"mercury_type_info.h"
 #ifdef MR_USE_TRAIL
 #include	"mercury_trail.h"
Index: runtime/mercury_memory.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_memory.c,v
retrieving revision 1.3
diff -u -r1.3 mercury_memory.c
--- mercury_memory.c	1997/11/23 09:31:49	1.3
+++ mercury_memory.c	1998/03/11 04:52:31
@@ -163,23 +163,18 @@
 
 static	void	setup_signal(void);
 
-Word	fake_reg[MAX_FAKE_REG];
-
 Word	virtual_reg_map[MAX_REAL_REG] = VIRTUAL_REG_MAP_BODY;
 
 unsigned long	num_uses[MAX_RN];
 
-MemoryZone *zone_table;
-
-MemoryZone *used_memory_zones;
-MemoryZone *free_memory_zones;
+MemoryZone *zone_table=NULL;
 
-MemoryZone *detstack_zone;
-MemoryZone *nondetstack_zone;
-#ifndef CONSERVATIVE_GC
-  MemoryZone *heap_zone;
-  MemoryZone *solutions_heap_zone;
+MemoryZone *used_memory_zones=NULL;
+MemoryZone *free_memory_zones=NULL;
+#ifdef	MR_THREAD_SAFE
+MercuryLock *free_memory_zones_lock;
 #endif
+
 #ifndef	SPEED
   MemoryZone *dumpstack_zone;
   int	dumpindex;
@@ -202,16 +197,20 @@
 #define	CACHE_SLICES	8
 
 static	size_t		*offset_vector;
-static	int		*offset_counter;
-static	SpinLock	*offset_lock;
+static	int		offset_counter;
 size_t	next_offset(void);
 
-static void init_memory_arena(void);
-static void init_zones(void);
+static void init_offsets(void);
 
 void 
 init_memory(void)
 {
+	static first_time_only=0;
+
+	if (first_time_only != 0)
+		return;
+	first_time_only = 1;
+
 	/*
 	** Convert all the sizes are from kilobytes to bytes and
 	** make sure they are multiples of the page and cache sizes.
@@ -274,8 +273,12 @@
 	}
 #endif
 
-	init_memory_arena();
-	init_zones();
+#ifdef	MR_THREAD_SAFE
+	free_memory_zones_lock = make(MercuryLock);
+	pthread_mutex_init(free_memory_zones_lock, MR_MUTEX_ATTR);
+#endif
+
+	init_offsets();
 	setup_signal();
 	if (memdebug) debug_memory();
 } /* end init_memory() */
@@ -294,11 +297,11 @@
 		(unsigned long) unit, (unsigned long) unit);
 
 	fprintf(stderr, "\n");
-	fprintf(stderr, "fake_reg       = %p (offset %ld)\n",
-		(void *) fake_reg, (long) fake_reg & (unit-1));
+	fprintf(stderr, "MR_fake_reg       = %p (offset %ld)\n",
+		(void *) MR_fake_reg, (long) MR_fake_reg & (unit-1));
 	fprintf(stderr, "\n");
 
-	for (zone = used_memory_zones; zone; zone = zone->next)
+	for (zone = used_memory_zones; zone != NULL ; zone = zone->next)
 	{
 		fprintf(stderr, "%-16s#%d-base	= %p\n",
 			zone->name, zone->id, (void *) zone->bottom);
@@ -325,115 +328,25 @@
 	}
 }
 
-/*
-** init_memory_arena() allocates (if necessary) the top-level memory pool
-** from which all allocations should come. If PARALLEL is defined, then
-** this pool should be shared memory. In the absence of PARALLEL, it
-** doesn't need to do anything, since with CONSERVATIVE_GC, the collector
-** manages the heap, and without GC, we can allocate memory using memalign
-** or malloc.
-*/
-static void 
-init_memory_arena()
-{
-#ifdef	PARALLEL
-  #ifndef CONSERVATIVE_GC
-	if (numprocs > 1) {
-		fatal_error("shared memory not implemented");
-	}
-  #else
-	if (numprocs > 1) {
-		fatal_error("shared memory not implemented with conservative gc");
-	}
-  #endif
-#endif
-}
-
 static void 
-init_zones()
+init_offsets()
 {
 	int i;
 	size_t fake_reg_offset;
 
-	/*
-	** Allocate the MemoryZone table.
-	*/
-	zone_table = allocate_array(MemoryZone, MAX_ZONES);
-
-	/*
-	** Initialize the MemoryZone table.
-	*/
-	used_memory_zones = NULL;
-	free_memory_zones = zone_table;
-	for(i = 0; i < MAX_ZONES; i++) {
-		zone_table[i].name = "unused";
-		zone_table[i].id = i;
-		zone_table[i].bottom = NULL;
-		zone_table[i].top = NULL;
-		zone_table[i].min = NULL;
-#ifndef SPEED
-		zone_table[i].max = NULL;
-#endif
-#ifdef HAVE_MPROTECT
-  #ifdef HAVE_SIGINFO
-		zone_table[i].redzone = NULL;
-  #endif
-		zone_table[i].hardmax = NULL;
-#endif
-		if (i+1 < MAX_ZONES) {
-			zone_table[i].next = &(zone_table[i+1]);
-		} else {
-			zone_table[i].next = NULL;
-		}
-	}
-
-	offset_counter = allocate_object(int);
-	*offset_counter = 0;
+	offset_counter = 0;
 
 	offset_vector = allocate_array(size_t, CACHE_SLICES - 1);
 
-	fake_reg_offset = (Unsigned) fake_reg % pcache_size;
+	fake_reg_offset = (Unsigned) MR_fake_reg % pcache_size;
 
 	for (i = 0; i < CACHE_SLICES - 1; i++) {
 		offset_vector[i] =
 			(fake_reg_offset + pcache_size / CACHE_SLICES)
 			% pcache_size;
 	}
-} /* end init_zones() */
-
-
-void 
-init_heap(void)
-{
-#ifndef CONSERVATIVE_GC
-	heap_zone = create_zone("heap", 1, heap_size, next_offset(),
-			heap_zone_size, default_handler);
+} /* end init_offsets() */
 
-	restore_transient_registers();
-	MR_hp = heap_zone->min;
-	save_transient_registers();
-
-	solutions_heap_zone = create_zone("solutions_heap", 1,
-			solutions_heap_size, next_offset(),
-			solutions_heap_zone_size, default_handler);
-	restore_transient_registers();
-	MR_sol_hp = solutions_heap_zone->min;
-	save_transient_registers();
-
-#endif
-
-#ifndef SPEED
-	/*
-	** Create the dumpstack, used for debugging stack traces.
-	** Note that we can just make the dumpstack the same size as
-	** the detstack and we never have to worry about the dumpstack
-	** overflowing.
-	*/
-
-	dumpstack_zone = create_zone("dumpstack", 1, detstack_size,
-			next_offset(), detstack_zone_size, default_handler);
-#endif
-} /* end init_heap() */
 
 MemoryZone *
 get_zone(void)
@@ -444,14 +357,17 @@
 	** unlink the first zone on the free-list,
 	** link it onto the used-list and return it.
 	*/
-	zone = free_memory_zones;
-	if (zone == NULL) {
-		fatal_error("no more memory zones");
+	MR_LOCK(free_memory_zones_lock, "get_zone");
+	if (free_memory_zones == NULL) {
+		zone = (MemoryZone *) make(MemoryZone);
+	} else {
+		zone = free_memory_zones;
+		free_memory_zones = free_memory_zones->next;
 	}
-	free_memory_zones = free_memory_zones->next;
 
 	zone->next = used_memory_zones;
 	used_memory_zones = zone;
+	MR_UNLOCK(free_memory_zones_lock, "get_zone");
 
 	return zone;
 }
@@ -465,6 +381,7 @@
 	** Find the zone on the used list, and unlink it from
 	** the list, then link it onto the start of the free-list.
 	*/
+	MR_LOCK(free_memory_zones_lock, "unget_zone");
 	for(prev = NULL, tmp = used_memory_zones;
 		tmp && tmp != zone; prev = tmp, tmp = tmp->next) 
 	{
@@ -481,6 +398,7 @@
 
 	zone->next = free_memory_zones;
 	free_memory_zones = zone;
+	MR_UNLOCK(free_memory_zones_lock, "unget_zone");
 }
 
 /*
@@ -498,13 +416,9 @@
 {
 	size_t offset;
 
-	get_lock(offset_lock);
+	offset = offset_vector[offset_counter];
 
-	offset = offset_vector[*offset_counter];
-
-	*offset_counter = (*offset_counter + 1) % (CACHE_SLICES - 1);
-
-	release_lock(offset_lock);
+	offset_counter = (offset_counter + 1) % (CACHE_SLICES - 1);
 
 	return offset;
 }
@@ -530,11 +444,6 @@
 	total_size = size + unit;
 #endif
 
-#ifdef	PARALLEL
-	if (numprocs > 1) {
-		fatal_error("shared memory not supported yet");
-	}
-#endif
 	base = memalign(unit, total_size);
 	if (base == NULL) {
 		char buf[2560];
@@ -613,6 +522,9 @@
 reset_zone(MemoryZone *zone)
 {
 #if	defined(HAVE_MPROTECT) && defined(HAVE_SIGINFO)
+	if (zone->redzone == zone->redzone_base)
+		return;
+
 	zone->redzone = zone->redzone_base;
 
 	if (mprotect((char *)zone->redzone,
@@ -627,6 +539,34 @@
 #endif
 }
 
+void destroy_zone(MemoryZone *zone)
+{
+	size_t zone_size;
+
+	/*
+	** We'd better unprotect the memory, so that if we allocate
+	** it again later, we don't get into problems...
+	*/
+	zone_size = ((char *) zone->top) - ((char *) zone->redzone);
+	if (mprotect((char *)zone->redzone, zone_size,
+		    PROT_READ|PROT_WRITE) < 0)
+	{
+	    char buf[2560];
+	    sprintf(buf, "Mercury runtime: cannot unprotect %s#%d zone",
+		zone->name, zone->id);
+	    perror(buf);
+	    exit(1);
+	}
+
+	free(zone->bottom);
+
+	/*
+	** At the moment, we don't release the memory zone structure,
+	** we just put the zone on the free list.
+	*/
+	unget_zone(zone);
+}
+
 #define STDERR 2
 
 #ifdef	SPEED
@@ -1150,12 +1090,6 @@
 {
 	void	*tmp;
 
-  #ifdef	PARALLEL
-	if (numprocs > 1) {
-		fatal_error("shared memory not supported (yet)");
-	}
-  #endif
-
 	tmp = GC_MALLOC(numbytes);
 	
 	if (tmp == NULL) {
@@ -1165,23 +1099,13 @@
 	return tmp;
 }
 
-#elif defined(PARALLEL)
-
-  #error "shared memory not implemented"
-
-#else /* not CONSERVATIVE_GC && not PARALLEL */
+#else /* not CONSERVATIVE_GC */
 
 void *
 allocate_bytes(size_t numbytes)
 {
 	void	*tmp;
 
-  #ifdef	PARALLEL
-	if (numprocs > 1) {
-		fatal_error("shared memory not supported (yet)");
-	}
-  #endif
-
 	tmp = malloc(numbytes);
 	
 	if (tmp == NULL) {
@@ -1197,19 +1121,9 @@
 deallocate_memory(void *ptr)
 {
 #ifdef CONSERVATIVE_GC
-  #ifdef	PARALLEL
-	if (numprocs > 1) {
-		fatal_error("shared memory not supported");
-	}
-  #endif
 	GC_FREE(ptr);
 
 #else
-  #ifdef	PARALLEL
-	if (numprocs > 1) {
-		fatal_error("shared memory not supported");
-	}
-  #endif
 	free(ptr);
 #endif
 }
Index: runtime/mercury_memory.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_memory.h,v
retrieving revision 1.2
diff -u -r1.2 mercury_memory.h
--- mercury_memory.h	1997/11/23 07:21:28	1.2
+++ mercury_memory.h	1998/03/11 04:52:31
@@ -40,9 +40,6 @@
 #define MAX_FAKE_REG	(NUM_SPECIAL_REG + MAX_VIRTUAL_REG)
 				/* mr0 .. mr36, mr(37) ... mr(1028) */
 
-/* reserve MAX_FAKE_REG virtual regs, numbered from 0 to MAX_FAKE_REG-1 */
-extern	Word	fake_reg[MAX_FAKE_REG];
-
 /* used to lookup the fake_reg for a given real reg */
 extern	Word	virtual_reg_map[MAX_REAL_REG];
 
@@ -126,18 +123,6 @@
 	/* A linked list of all the used zones */
 extern MemoryZone	*used_memory_zones;
 
-extern MemoryZone	*detstack_zone;
-extern MemoryZone	*nondetstack_zone;
-#ifndef CONSERVATIVE_GC
-extern MemoryZone	*heap_zone;
-extern MemoryZone	*solutions_heap_zone;
-#endif
-
-#ifndef	SPEED
-extern	MemoryZone	*dumpstack_zone;
-extern	int		dumpindex;
-#endif
-
 /*
 ** create_zone(Name, Id, Size, Offset, RedZoneSize, FaultHandler)
 ** allocates a new memory zone with name Name, and number Id, size
@@ -155,6 +140,12 @@
 MemoryZone	*create_zone(const char *name, int id,
 			size_t size, size_t offset, size_t redsize,
 			ZoneHandler *handler);
+
+/*
+** destroy_zone(Zone) destroys a memory zone.
+*/
+
+void	destroy_zone(MemoryZone *zone);
 
 /*
 ** construct_zone(Name, Id, Base, Size, Offset, RedZoneSize, FaultHandler)
Index: runtime/mercury_misc.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_misc.c,v
retrieving revision 1.3
diff -u -r1.3 mercury_misc.c
--- mercury_misc.c	1998/01/23 15:26:33	1.3
+++ mercury_misc.c	1998/03/18 23:48:42
@@ -488,6 +488,13 @@
 	return p;
 }
 
+void
+MR_copy_structure(char *dest, const char *src, size_t nbytes)
+{
+	while (nbytes-- > 0)
+		*dest++ = *src++;
+}
+
 /*
 **  Note that hash_string is actually defined as a macro in mercury_imp.h,
 **  if we're using GNU C.  We define it here whether or not we're using
@@ -502,3 +509,4 @@
 {
 	HASH_STRING_FUNC_BODY
 }
+
Index: runtime/mercury_misc.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_misc.h,v
retrieving revision 1.3
diff -u -r1.3 mercury_misc.h
--- mercury_misc.h	1998/01/23 15:26:35	1.3
+++ mercury_misc.h	1998/03/18 23:45:05
@@ -4,7 +4,12 @@
 ** Public License - see the file COPYING.LIB in the Mercury distribution.
 */
 
-/* mercury_misc.h - debugging messages, fatal_error(), and checked_malloc() */
+/*
+** mercury_misc.h -	debugging messages,
+**			fatal_error(),
+**			checked_malloc(),
+**			MR_copy_structure
+*/
 
 #ifndef	MERCURY_MISC_H
 #define	MERCURY_MISC_H
@@ -68,5 +73,7 @@
 */
 #include <stddef.h>	/* for size_t */
 void *checked_malloc(size_t n);
+
+void MR_copy_structure(char *dest, const char *src, size_t nbytes);
 
 #endif /* not MERCURY_MISC_H */
Index: runtime/mercury_regorder.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_regorder.h,v
retrieving revision 1.2
diff -u -r1.2 mercury_regorder.h
--- mercury_regorder.h	1997/11/23 07:21:32	1.2
+++ mercury_regorder.h	1998/03/11 04:52:31
@@ -22,6 +22,99 @@
 #ifndef MERCURY_REGORDER_H
 #define MERCURY_REGORDER_H
 
+#if defined(MR_THREAD_SAFE) && NUM_REAL_REGS > 0
+
+#define r1		count_usage(R_RN(1), mr3)
+#define r2		count_usage(R_RN(2), mr4)
+#define r3		count_usage(R_RN(3), mr5)
+#define r4		count_usage(R_RN(4), mr7)
+#define r5		count_usage(R_RN(5), mr8)
+#define r6		count_usage(R_RN(6), mr11)
+#define r7		count_usage(R_RN(7), mr12)
+#define r8		count_usage(R_RN(8), mr13)
+#define r9		count_usage(R_RN(9), mr14)
+#define r10		count_usage(R_RN(10), mr15)
+#define r11		count_usage(R_RN(11), mr16)
+#define r12		count_usage(R_RN(12), mr17)
+#define r13		count_usage(R_RN(13), mr19)
+#define r14		count_usage(R_RN(14), mr19)
+#define r15		count_usage(R_RN(15), mr20)
+#define r16		count_usage(R_RN(16), mr21)
+#define r17		count_usage(R_RN(17), mr22)
+#define r18		count_usage(R_RN(18), mr23)
+#define r19		count_usage(R_RN(19), mr24)
+#define r20		count_usage(R_RN(20), mr25)
+#define r21		count_usage(R_RN(21), mr26)
+#define r22		count_usage(R_RN(22), mr27)
+#define r23		count_usage(R_RN(23), mr28)
+#define r24		count_usage(R_RN(24), mr29)
+#define r25		count_usage(R_RN(25), mr30)
+#define r26		count_usage(R_RN(26), mr31)
+#define r27		count_usage(R_RN(27), mr32)
+#define r28		count_usage(R_RN(28), mr33)
+#define r29		count_usage(R_RN(29), mr34)
+#define r30		count_usage(R_RN(30), mr35)
+#define r31		count_usage(R_RN(31), mr36)
+#define r32		count_usage(R_RN(32), mr37)
+
+#define MR_engine_base	LVALUE_CAST(Word *, count_usage(MR_SP_RN, mr0))
+
+#define MR_succip	LVALUE_CAST(Code *, count_usage(MR_SI_RN, mr2))
+#define succip		MR_succip
+#define MR_hp		LVALUE_CAST(Word *, count_usage(MR_HP_RN, mr6))
+#define hp		MR_hp
+#define MR_sp		LVALUE_CAST(Word *, count_usage(MR_SP_RN, mr1))
+#define sp		MR_sp
+#define MR_curfr	LVALUE_CAST(Word *, count_usage(MR_CF_RN, mr9))
+#define curfr		MR_curfr
+#define MR_maxfr	LVALUE_CAST(Word *, count_usage(MR_MF_RN, mr10))
+#define maxfr		MR_maxfr
+#define MR_sol_hp	LVALUE_CAST(Word *, count_usage(MR_SOL_HP_RN, mr(38)))
+#define MR_min_hp_rec	LVALUE_CAST(Word *, count_usage(MR_MIN_HP_REC, mr(39)))
+#define MR_min_sol_hp_rec	LVALUE_CAST(Word *,	\
+			count_usage(MR_MIN_HP_REC, mr40))
+
+#define MR_trail_ptr	count_usage(MR_TRAIL_PTR_RN, MR_trail_ptr_var)
+#define MR_ticket_counter	 \
+		count_usage(MR_TICKET_COUNTER_RN, MR_ticket_counter_var)
+
+#define VIRTUAL_REG_MAP_BODY	{ \
+	3, \
+	4, \
+	5, \
+	7, \
+	8, \
+	11, \
+	12, \
+	13, \
+	14, \
+	15, \
+	16, \
+	17, \
+	18, \
+	19, \
+	20, \
+	21, \
+	22, \
+	23, \
+	24, \
+	25, \
+	26, \
+	27, \
+	28, \
+	29, \
+	30, \
+	31, \
+	32, \
+	33, \
+	34, \
+	35, \
+	36, \
+	37, \
+}
+
+#else /* !MR_THREAD_SAFE or NUM_REAL_REGS == 0 */
+
 #define r1		count_usage(R_RN(1), mr2)
 #define r2		count_usage(R_RN(2), mr3)
 #define r3		count_usage(R_RN(3), mr4)
@@ -108,5 +201,7 @@
 	35, \
 	36, \
 }
+
+#endif
 
 #endif /* not MERCURY_REGORDER_H */
Index: runtime/mercury_regs.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_regs.h,v
retrieving revision 1.5
diff -u -r1.5 mercury_regs.h
--- mercury_regs.h	1998/02/04 03:55:27	1.5
+++ mercury_regs.h	1998/03/11 04:52:31
@@ -28,6 +28,7 @@
   #define LVALUE_COND(expr, x, y)	(*((expr)?&(x):&(y)))
 #endif
 
+#define MR_fake_reg	(MR_ENGINE(fake_reg))
 /*
 ** The registers of the Mercury virtual machine are built up using
 ** three levels of abstraction.
@@ -83,7 +84,7 @@
 
 #define mr(n) LVALUE_SEQ(MR_assert((n) >= MAX_REAL_REG + NUM_SPECIAL_REG && \
 				(n) < MAX_FAKE_REG),\
-		fake_reg[n])
+		MR_fake_reg[n])
 
 #ifdef MEASURE_REGISTER_USAGE
   #define count_usage(num,reg)		LVALUE_SEQ(num_uses[num]++, reg)
@@ -99,17 +100,28 @@
 
 /* 
 ** the save_registers() macro copies the physical machine registers
-** to their corresponding slots in the fake_reg array 
+** to their corresponding slots in the MR_fake_reg array 
 */
 
-#define save_registers() 	save_regs_to_mem(fake_reg)
+#define save_registers() 	save_regs_to_mem(MR_fake_reg)
 
 /* 
 ** the restore_registers() macro sets the physical machine registers
 ** to the values in their corresponding slots in the fake_reg array 
+** If we're using a register for the engine base, then we'd better
+** restore that from the thread specific data area, since the fake_reg
+** array is accessed via that register.
 */
 
-#define restore_registers() 	restore_regs_from_mem(fake_reg)
+#if defined(MR_THREAD_SAFE) && NUM_REAL_REGS > 0
+#define	restore_registers()	do {				\
+		MR_engine_base = MR_thread_engine_base;		\
+		MR_fake_reg[0] = (Word) MR_engine_base;		\
+		restore_regs_from_mem(MR_fake_reg);		\
+	} while (0)
+#else
+#define restore_registers() 	restore_regs_from_mem(MR_fake_reg)
+#endif
 
 /* 
 ** the save_transient_registers() and restore_transient_registers()
@@ -119,15 +131,24 @@
 ** by sliding register windows on SPARCs).
 */
 
-#define save_transient_registers()    save_transient_regs_to_mem(fake_reg)
-#define restore_transient_registers() restore_transient_regs_from_mem(fake_reg)
+#define save_transient_registers()    save_transient_regs_to_mem(MR_fake_reg)
+#if defined(MR_THREAD_SAFE) && NUM_REAL_REGS > 0
+#define restore_transient_registers()	do {				\
+		MR_engine_base = MR_thread_engine_base;			\
+		MR_fake_reg[0] = (Word) MR_engine_base;			\
+		restore_transient_regs_from_mem(MR_fake_reg);		\
+	} while (0)
+#else
+#define restore_transient_registers()	\
+		restore_transient_regs_from_mem(MR_fake_reg)
+#endif
 
 /* virtual_reg(n) accesses the underlying fake_reg for register n */
 
 #define virtual_reg(n)	\
 	LVALUE_COND((n) > MAX_REAL_REG, \
 		r(n), \
-		fake_reg[virtual_reg_map[(n) - 1]])
+		MR_fake_reg[virtual_reg_map[(n) - 1]])
 
 /* saved_reg(save_area, n) is like virtual_reg, except in that */
 /* it accesses the given save area instead of the machine regs and fake_reg */
Index: runtime/mercury_trace.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_trace.c,v
retrieving revision 1.7
diff -u -r1.7 mercury_trace.c
--- mercury_trace.c	1998/02/04 03:55:31	1.7
+++ mercury_trace.c	1998/03/11 04:52:32
@@ -351,7 +351,7 @@
 
 	save_regs_to_mem(MR_saved_regs);
 	for (i = NUM_REAL_REGS; i < MAX_FAKE_REG; i++)
-		MR_saved_regs[i] = fake_reg[i];
+		MR_saved_regs[i] = MR_ENGINE(fake_reg)[i];
 
 	for (i = 0; i < var_count; i++) {
 		if (vars->MR_slvs_names != NULL &&
@@ -365,7 +365,7 @@
 
 	restore_regs_from_mem(MR_saved_regs);
 	for (i = NUM_REAL_REGS; i < MAX_FAKE_REG; i++)
-		 fake_reg[i] = MR_saved_regs[i];
+		 MR_ENGINE(fake_reg)[i] = MR_saved_regs[i];
 }
 
 /* if you want to debug this code, you may want to set this var to 1 */
Index: runtime/mercury_wrapper.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.6
diff -u -r1.6 mercury_wrapper.c
--- mercury_wrapper.c	1998/02/03 08:17:31	1.6
+++ mercury_wrapper.c	1998/03/11 04:52:33
@@ -74,6 +74,8 @@
 static	bool	use_own_timer = FALSE;
 static	int	repeats = 1;
 
+unsigned	MR_num_threads = 1;
+
 /* timing */
 int		time_at_last_stat;
 int		time_at_start;
@@ -196,7 +198,7 @@
 
 	/* double-check that the garbage collector knows about
 	   global variables in shared libraries */
-	GC_is_visible(fake_reg);
+	GC_is_visible(&MR_runqueue);
 
 	/* The following code is necessary to tell the conservative */
 	/* garbage collector that we are using tagged pointers */
@@ -222,7 +224,18 @@
 	(*address_of_mercury_init_io)();
 
 	/* start up the Mercury engine */
-	init_engine();
+#ifndef MR_THREAD_SAFE
+	init_thread((void *) 1);
+#else
+	{
+		int i;
+		init_thread_stuff();
+		init_thread((void *)1);
+		MR_exit_now = FALSE;
+		for (i = 1 ; i < MR_num_threads ; i++)
+			create_thread(0);
+	}
+#endif
 
 	/* initialize profiling */
 	if (MR_profiling) MR_prof_init();
@@ -240,6 +253,8 @@
 	/* initialize the Mercury library */
 	(*MR_library_initializer)();
 
+	save_context(&(MR_ENGINE(context)));
+
 	/*
 	** Restore the callee-save registers before returning,
 	** since they may be used by the C code that called us.
@@ -531,12 +546,12 @@
 			MR_profiling = FALSE;
 			break;
 
-#ifdef	PARALLEL
+#ifdef	MR_THREAD_SAFE
 		case 'P':
-				if (sscanf(optarg, "%u", &numprocs) != 1)
+				if (sscanf(optarg, "%u", &MR_num_threads) != 1)
 					usage();
 				
-				if (numprocs < 1)
+				if (MR_num_threads < 1)
 					usage();
 
 				break;
@@ -963,6 +978,11 @@
 	(*MR_library_finalizer)();
 
 	if (MR_profiling) MR_prof_finish();
+
+#ifdef	MR_THREAD_SAFE
+	MR_exit_now = TRUE;
+	pthread_cond_broadcast(MR_runqueue_cond);
+#endif
 
 	terminate_engine();
 
cvs diff: Diffing runtime/machdeps
Index: runtime/machdeps/alpha_regs.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/machdeps/alpha_regs.h,v
retrieving revision 1.8
diff -u -r1.8 alpha_regs.h
--- alpha_regs.h	1997/07/27 15:09:06	1.8
+++ alpha_regs.h	1998/03/11 04:52:33
@@ -57,35 +57,36 @@
 #define save_transient_regs_to_mem(save_area)		((void)0)
 #define restore_transient_regs_from_mem(save_area)	((void)0)
 
-#define	mr7	fake_reg[7]
-#define	mr8	fake_reg[8]
-#define	mr9	fake_reg[9]
-#define	mr10	fake_reg[10]
-#define	mr11	fake_reg[11]
-#define	mr12	fake_reg[12]
-#define	mr13	fake_reg[13]
-#define	mr14	fake_reg[14]
-#define	mr15	fake_reg[15]
-#define	mr16	fake_reg[16]
-#define	mr17	fake_reg[17]
-#define	mr18	fake_reg[18]
-#define	mr19	fake_reg[19]
-#define	mr20	fake_reg[20]
-#define	mr21	fake_reg[21]
-#define	mr22	fake_reg[22]
-#define	mr23	fake_reg[23]
-#define	mr24	fake_reg[24]
-#define	mr25	fake_reg[25]
-#define	mr26	fake_reg[26]
-#define	mr27	fake_reg[27]
-#define	mr28	fake_reg[28]
-#define	mr29	fake_reg[29]
-#define	mr30	fake_reg[30]
-#define	mr31	fake_reg[31]
-#define	mr32	fake_reg[32]
-#define	mr33	fake_reg[33]
-#define	mr34	fake_reg[34]
-#define	mr35	fake_reg[35]
-#define	mr36	fake_reg[36]
+#define	mr7	MR_fake_reg[7]
+#define	mr8	MR_fake_reg[8]
+#define	mr9	MR_fake_reg[9]
+#define	mr10	MR_fake_reg[10]
+#define	mr11	MR_fake_reg[11]
+#define	mr12	MR_fake_reg[12]
+#define	mr13	MR_fake_reg[13]
+#define	mr14	MR_fake_reg[14]
+#define	mr15	MR_fake_reg[15]
+#define	mr16	MR_fake_reg[16]
+#define	mr17	MR_fake_reg[17]
+#define	mr18	MR_fake_reg[18]
+#define	mr19	MR_fake_reg[19]
+#define	mr20	MR_fake_reg[20]
+#define	mr21	MR_fake_reg[21]
+#define	mr22	MR_fake_reg[22]
+#define	mr23	MR_fake_reg[23]
+#define	mr24	MR_fake_reg[24]
+#define	mr25	MR_fake_reg[25]
+#define	mr26	MR_fake_reg[26]
+#define	mr27	MR_fake_reg[27]
+#define	mr28	MR_fake_reg[28]
+#define	mr29	MR_fake_reg[29]
+#define	mr30	MR_fake_reg[30]
+#define	mr31	MR_fake_reg[31]
+#define	mr32	MR_fake_reg[32]
+#define	mr33	MR_fake_reg[33]
+#define	mr34	MR_fake_reg[34]
+#define	mr35	MR_fake_reg[35]
+#define	mr36	MR_fake_reg[36]
+#define	mr37	MR_fake_reg[37]
 
 #endif /* not ALPHA_REGS_H */
Index: runtime/machdeps/i386_regs.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/machdeps/i386_regs.h,v
retrieving revision 1.13
diff -u -r1.13 i386_regs.h
--- i386_regs.h	1997/07/27 15:09:07	1.13
+++ i386_regs.h	1998/03/18 03:48:41
@@ -62,7 +62,7 @@
 register	Word	mr1 __asm__("edi");	/* succip */
 
 #if PIC_REG
-  #define mr2	fake_reg[2]
+  #define mr2	MR_fake_reg[2]
 #else
   register	Word	mr2 __asm__("ebx");	/* r1 */
 #endif
@@ -102,39 +102,40 @@
 #define save_transient_regs_to_mem(save_area)		((void)0)
 #define restore_transient_regs_from_mem(save_area)	((void)0)
 
-#define	mr3	fake_reg[3]
-#define	mr4	fake_reg[4]
-#define	mr5	fake_reg[5]
-#define	mr6	fake_reg[6]
-#define	mr7	fake_reg[7]
-#define	mr8	fake_reg[8]
-#define	mr9	fake_reg[9]
-#define	mr10	fake_reg[10]
-#define	mr11	fake_reg[11]
-#define	mr12	fake_reg[12]
-#define	mr13	fake_reg[13]
-#define	mr14	fake_reg[14]
-#define	mr15	fake_reg[15]
-#define	mr16	fake_reg[16]
-#define	mr17	fake_reg[17]
-#define	mr18	fake_reg[18]
-#define	mr19	fake_reg[19]
-#define	mr20	fake_reg[20]
-#define	mr21	fake_reg[21]
-#define	mr22	fake_reg[22]
-#define	mr23	fake_reg[23]
-#define	mr24	fake_reg[24]
-#define	mr25	fake_reg[25]
-#define	mr26	fake_reg[26]
-#define	mr27	fake_reg[27]
-#define	mr28	fake_reg[28]
-#define	mr29	fake_reg[29]
-#define	mr30	fake_reg[30]
-#define	mr31	fake_reg[31]
-#define	mr32	fake_reg[32]
-#define	mr33	fake_reg[33]
-#define	mr34	fake_reg[34]
-#define	mr35	fake_reg[35]
-#define	mr36	fake_reg[36]
+#define	mr3	MR_fake_reg[3]
+#define	mr4	MR_fake_reg[4]
+#define	mr5	MR_fake_reg[5]
+#define	mr6	MR_fake_reg[6]
+#define	mr7	MR_fake_reg[7]
+#define	mr8	MR_fake_reg[8]
+#define	mr9	MR_fake_reg[9]
+#define	mr10	MR_fake_reg[10]
+#define	mr11	MR_fake_reg[11]
+#define	mr12	MR_fake_reg[12]
+#define	mr13	MR_fake_reg[13]
+#define	mr14	MR_fake_reg[14]
+#define	mr15	MR_fake_reg[15]
+#define	mr16	MR_fake_reg[16]
+#define	mr17	MR_fake_reg[17]
+#define	mr18	MR_fake_reg[18]
+#define	mr19	MR_fake_reg[19]
+#define	mr20	MR_fake_reg[20]
+#define	mr21	MR_fake_reg[21]
+#define	mr22	MR_fake_reg[22]
+#define	mr23	MR_fake_reg[23]
+#define	mr24	MR_fake_reg[24]
+#define	mr25	MR_fake_reg[25]
+#define	mr26	MR_fake_reg[26]
+#define	mr27	MR_fake_reg[27]
+#define	mr28	MR_fake_reg[28]
+#define	mr29	MR_fake_reg[29]
+#define	mr30	MR_fake_reg[30]
+#define	mr31	MR_fake_reg[31]
+#define	mr32	MR_fake_reg[32]
+#define	mr33	MR_fake_reg[33]
+#define	mr34	MR_fake_reg[34]
+#define	mr35	MR_fake_reg[35]
+#define	mr36	MR_fake_reg[36]
+#define	mr37	MR_fake_reg[37]
 
 #endif /* not I386_REGS_H */
Index: runtime/machdeps/m68k.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/machdeps/m68k.h,v
retrieving revision 1.1
diff -u -r1.1 m68k.h
--- m68k.h	1997/08/15 15:32:08	1.1
+++ m68k.h	1998/03/11 04:52:33
@@ -62,37 +62,38 @@
 #define save_transient_regs_to_mem(save_area)		((void)0)
 #define restore_transient_regs_from_mem(save_area)	((void)0)
 
-#define	mr5	fake_reg[5]
-#define	mr6	fake_reg[6]
-#define	mr7	fake_reg[7]
-#define	mr8	fake_reg[8]
-#define	mr9	fake_reg[9]
-#define	mr10	fake_reg[10]
-#define	mr11	fake_reg[11]
-#define	mr12	fake_reg[12]
-#define	mr13	fake_reg[13]
-#define	mr14	fake_reg[14]
-#define	mr15	fake_reg[15]
-#define	mr16	fake_reg[16]
-#define	mr17	fake_reg[17]
-#define	mr18	fake_reg[18]
-#define	mr19	fake_reg[19]
-#define	mr20	fake_reg[20]
-#define	mr21	fake_reg[21]
-#define	mr22	fake_reg[22]
-#define	mr23	fake_reg[23]
-#define	mr24	fake_reg[24]
-#define	mr25	fake_reg[25]
-#define	mr26	fake_reg[26]
-#define	mr27	fake_reg[27]
-#define	mr28	fake_reg[28]
-#define	mr29	fake_reg[29]
-#define	mr30	fake_reg[30]
-#define	mr31	fake_reg[31]
-#define	mr32	fake_reg[32]
-#define	mr33	fake_reg[33]
-#define	mr34	fake_reg[34]
-#define	mr35	fake_reg[35]
-#define	mr36	fake_reg[36]
+#define	mr5	MR_fake_reg[5]
+#define	mr6	MR_fake_reg[6]
+#define	mr7	MR_fake_reg[7]
+#define	mr8	MR_fake_reg[8]
+#define	mr9	MR_fake_reg[9]
+#define	mr10	MR_fake_reg[10]
+#define	mr11	MR_fake_reg[11]
+#define	mr12	MR_fake_reg[12]
+#define	mr13	MR_fake_reg[13]
+#define	mr14	MR_fake_reg[14]
+#define	mr15	MR_fake_reg[15]
+#define	mr16	MR_fake_reg[16]
+#define	mr17	MR_fake_reg[17]
+#define	mr18	MR_fake_reg[18]
+#define	mr19	MR_fake_reg[19]
+#define	mr20	MR_fake_reg[20]
+#define	mr21	MR_fake_reg[21]
+#define	mr22	MR_fake_reg[22]
+#define	mr23	MR_fake_reg[23]
+#define	mr24	MR_fake_reg[24]
+#define	mr25	MR_fake_reg[25]
+#define	mr26	MR_fake_reg[26]
+#define	mr27	MR_fake_reg[27]
+#define	mr28	MR_fake_reg[28]
+#define	mr29	MR_fake_reg[29]
+#define	mr30	MR_fake_reg[30]
+#define	mr31	MR_fake_reg[31]
+#define	mr32	MR_fake_reg[32]
+#define	mr33	MR_fake_reg[33]
+#define	mr34	MR_fake_reg[34]
+#define	mr35	MR_fake_reg[35]
+#define	mr36	MR_fake_reg[36]
+#define	mr37	MR_fake_reg[37]
 
 #endif /* not M68K_REGS_H */
Index: runtime/machdeps/mips_regs.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/machdeps/mips_regs.h,v
retrieving revision 1.11
diff -u -r1.11 mips_regs.h
--- mips_regs.h	1997/07/27 15:09:08	1.11
+++ mips_regs.h	1998/03/11 04:52:33
@@ -54,34 +54,35 @@
 #define save_transient_regs_to_mem(save_area)		((void)0)
 #define restore_transient_regs_from_mem(save_area)	((void)0)
 
-#define	mr8	fake_reg[8]
-#define	mr9	fake_reg[9]
-#define	mr10	fake_reg[10]
-#define	mr11	fake_reg[11]
-#define	mr12	fake_reg[12]
-#define	mr13	fake_reg[13]
-#define	mr14	fake_reg[14]
-#define	mr15	fake_reg[15]
-#define	mr16	fake_reg[16]
-#define	mr17	fake_reg[17]
-#define	mr18	fake_reg[18]
-#define	mr19	fake_reg[19]
-#define	mr20	fake_reg[20]
-#define	mr21	fake_reg[21]
-#define	mr22	fake_reg[22]
-#define	mr23	fake_reg[23]
-#define	mr24	fake_reg[24]
-#define	mr25	fake_reg[25]
-#define	mr26	fake_reg[26]
-#define	mr27	fake_reg[27]
-#define	mr28	fake_reg[28]
-#define	mr29	fake_reg[29]
-#define	mr30	fake_reg[30]
-#define	mr31	fake_reg[31]
-#define	mr32	fake_reg[32]
-#define	mr33	fake_reg[33]
-#define	mr34	fake_reg[34]
-#define	mr35	fake_reg[35]
-#define	mr36	fake_reg[36]
+#define	mr8	MR_fake_reg[8]
+#define	mr9	MR_fake_reg[9]
+#define	mr10	MR_fake_reg[10]
+#define	mr11	MR_fake_reg[11]
+#define	mr12	MR_fake_reg[12]
+#define	mr13	MR_fake_reg[13]
+#define	mr14	MR_fake_reg[14]
+#define	mr15	MR_fake_reg[15]
+#define	mr16	MR_fake_reg[16]
+#define	mr17	MR_fake_reg[17]
+#define	mr18	MR_fake_reg[18]
+#define	mr19	MR_fake_reg[19]
+#define	mr20	MR_fake_reg[20]
+#define	mr21	MR_fake_reg[21]
+#define	mr22	MR_fake_reg[22]
+#define	mr23	MR_fake_reg[23]
+#define	mr24	MR_fake_reg[24]
+#define	mr25	MR_fake_reg[25]
+#define	mr26	MR_fake_reg[26]
+#define	mr27	MR_fake_reg[27]
+#define	mr28	MR_fake_reg[28]
+#define	mr29	MR_fake_reg[29]
+#define	mr30	MR_fake_reg[30]
+#define	mr31	MR_fake_reg[31]
+#define	mr32	MR_fake_reg[32]
+#define	mr33	MR_fake_reg[33]
+#define	mr34	MR_fake_reg[34]
+#define	mr35	MR_fake_reg[35]
+#define	mr36	MR_fake_reg[36]
+#define	mr37	MR_fake_reg[37]
 
 #endif /* not MIPS_REGS_H */
Index: runtime/machdeps/no_regs.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/machdeps/no_regs.h,v
retrieving revision 1.10
diff -u -r1.10 no_regs.h
--- no_regs.h	1997/07/27 15:09:09	1.10
+++ no_regs.h	1998/03/11 04:52:34
@@ -38,46 +38,47 @@
 #define restore_transient_regs_from_mem(save_area)	((void)0)
 
 /* mr0, ..., mr36 are macros that map to either the underlying physical
-   machine register, if there is one, or otherwise to fake_reg[n].
+   machine register, if there is one, or otherwise to MR_fake_reg[n].
    For register numbers greater than 36, use mr(n).
 */
 
-#define	mr0	fake_reg[0]
-#define	mr1	fake_reg[1]
-#define	mr2	fake_reg[2]
-#define	mr3	fake_reg[3]
-#define	mr4	fake_reg[4]
-#define	mr5	fake_reg[5]
-#define	mr6	fake_reg[6]
-#define	mr7	fake_reg[7]
-#define	mr8	fake_reg[8]
-#define	mr9	fake_reg[9]
-#define	mr10	fake_reg[10]
-#define	mr11	fake_reg[11]
-#define	mr12	fake_reg[12]
-#define	mr13	fake_reg[13]
-#define	mr14	fake_reg[14]
-#define	mr15	fake_reg[15]
-#define	mr16	fake_reg[16]
-#define	mr17	fake_reg[17]
-#define	mr18	fake_reg[18]
-#define	mr19	fake_reg[19]
-#define	mr20	fake_reg[20]
-#define	mr21	fake_reg[21]
-#define	mr22	fake_reg[22]
-#define	mr23	fake_reg[23]
-#define	mr24	fake_reg[24]
-#define	mr25	fake_reg[25]
-#define	mr26	fake_reg[26]
-#define	mr27	fake_reg[27]
-#define	mr28	fake_reg[28]
-#define	mr29	fake_reg[29]
-#define	mr30	fake_reg[30]
-#define	mr31	fake_reg[31]
-#define	mr32	fake_reg[32]
-#define	mr33	fake_reg[33]
-#define	mr34	fake_reg[34]
-#define	mr35	fake_reg[35]
-#define	mr36	fake_reg[36]
+#define	mr0	MR_fake_reg[0]
+#define	mr1	MR_fake_reg[1]
+#define	mr2	MR_fake_reg[2]
+#define	mr3	MR_fake_reg[3]
+#define	mr4	MR_fake_reg[4]
+#define	mr5	MR_fake_reg[5]
+#define	mr6	MR_fake_reg[6]
+#define	mr7	MR_fake_reg[7]
+#define	mr8	MR_fake_reg[8]
+#define	mr9	MR_fake_reg[9]
+#define	mr10	MR_fake_reg[10]
+#define	mr11	MR_fake_reg[11]
+#define	mr12	MR_fake_reg[12]
+#define	mr13	MR_fake_reg[13]
+#define	mr14	MR_fake_reg[14]
+#define	mr15	MR_fake_reg[15]
+#define	mr16	MR_fake_reg[16]
+#define	mr17	MR_fake_reg[17]
+#define	mr18	MR_fake_reg[18]
+#define	mr19	MR_fake_reg[19]
+#define	mr20	MR_fake_reg[20]
+#define	mr21	MR_fake_reg[21]
+#define	mr22	MR_fake_reg[22]
+#define	mr23	MR_fake_reg[23]
+#define	mr24	MR_fake_reg[24]
+#define	mr25	MR_fake_reg[25]
+#define	mr26	MR_fake_reg[26]
+#define	mr27	MR_fake_reg[27]
+#define	mr28	MR_fake_reg[28]
+#define	mr29	MR_fake_reg[29]
+#define	mr30	MR_fake_reg[30]
+#define	mr31	MR_fake_reg[31]
+#define	mr32	MR_fake_reg[32]
+#define	mr33	MR_fake_reg[33]
+#define	mr34	MR_fake_reg[34]
+#define	mr35	MR_fake_reg[35]
+#define	mr36	MR_fake_reg[36]
+#define	mr37	MR_fake_reg[37]
 
 #endif /* not NO_REGS_H */
Index: runtime/machdeps/pa_regs.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/machdeps/pa_regs.h,v
retrieving revision 1.4
diff -u -r1.4 pa_regs.h
--- pa_regs.h	1997/07/27 15:09:10	1.4
+++ pa_regs.h	1998/03/11 04:52:34
@@ -54,34 +54,35 @@
 #define save_transient_regs_to_mem(save_area)		((void)0)
 #define restore_transient_regs_from_mem(save_area)	((void)0)
 
-#define	mr8	fake_reg[8]
-#define	mr9	fake_reg[9]
-#define	mr10	fake_reg[10]
-#define	mr11	fake_reg[11]
-#define	mr12	fake_reg[12]
-#define	mr13	fake_reg[13]
-#define	mr14	fake_reg[14]
-#define	mr15	fake_reg[15]
-#define	mr16	fake_reg[16]
-#define	mr17	fake_reg[17]
-#define	mr18	fake_reg[18]
-#define	mr19	fake_reg[19]
-#define	mr20	fake_reg[20]
-#define	mr21	fake_reg[21]
-#define	mr22	fake_reg[22]
-#define	mr23	fake_reg[23]
-#define	mr24	fake_reg[24]
-#define	mr25	fake_reg[25]
-#define	mr26	fake_reg[26]
-#define	mr27	fake_reg[27]
-#define	mr28	fake_reg[28]
-#define	mr29	fake_reg[29]
-#define	mr30	fake_reg[30]
-#define	mr31	fake_reg[31]
-#define	mr32	fake_reg[32]
-#define	mr33	fake_reg[33]
-#define	mr34	fake_reg[34]
-#define	mr35	fake_reg[35]
-#define	mr36	fake_reg[36]
+#define	mr8	MR_fake_reg[8]
+#define	mr9	MR_fake_reg[9]
+#define	mr10	MR_fake_reg[10]
+#define	mr11	MR_fake_reg[11]
+#define	mr12	MR_fake_reg[12]
+#define	mr13	MR_fake_reg[13]
+#define	mr14	MR_fake_reg[14]
+#define	mr15	MR_fake_reg[15]
+#define	mr16	MR_fake_reg[16]
+#define	mr17	MR_fake_reg[17]
+#define	mr18	MR_fake_reg[18]
+#define	mr19	MR_fake_reg[19]
+#define	mr20	MR_fake_reg[20]
+#define	mr21	MR_fake_reg[21]
+#define	mr22	MR_fake_reg[22]
+#define	mr23	MR_fake_reg[23]
+#define	mr24	MR_fake_reg[24]
+#define	mr25	MR_fake_reg[25]
+#define	mr26	MR_fake_reg[26]
+#define	mr27	MR_fake_reg[27]
+#define	mr28	MR_fake_reg[28]
+#define	mr29	MR_fake_reg[29]
+#define	mr30	MR_fake_reg[30]
+#define	mr31	MR_fake_reg[31]
+#define	mr32	MR_fake_reg[32]
+#define	mr33	MR_fake_reg[33]
+#define	mr34	MR_fake_reg[34]
+#define	mr35	MR_fake_reg[35]
+#define	mr36	MR_fake_reg[36]
+#define	mr37	MR_fake_reg[37]
 
 #endif /* not PA_REGS_H */
Index: runtime/machdeps/rs6000_regs.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/machdeps/rs6000_regs.h,v
retrieving revision 1.7
diff -u -r1.7 rs6000_regs.h
--- rs6000_regs.h	1997/12/18 03:15:50	1.7
+++ rs6000_regs.h	1998/03/11 04:52:34
@@ -61,32 +61,33 @@
 #define save_transient_regs_to_mem(save_area)		((void)0)
 #define restore_transient_regs_from_mem(save_area)	((void)0)
 
-#define	mr10	fake_reg[10]
-#define	mr11	fake_reg[11]
-#define	mr12	fake_reg[12]
-#define	mr13	fake_reg[13]
-#define	mr14	fake_reg[14]
-#define	mr15	fake_reg[15]
-#define	mr16	fake_reg[16]
-#define	mr17	fake_reg[17]
-#define	mr18	fake_reg[18]
-#define	mr19	fake_reg[19]
-#define	mr20	fake_reg[20]
-#define	mr21	fake_reg[21]
-#define	mr22	fake_reg[22]
-#define	mr23	fake_reg[23]
-#define	mr24	fake_reg[24]
-#define	mr25	fake_reg[25]
-#define	mr26	fake_reg[26]
-#define	mr27	fake_reg[27]
-#define	mr28	fake_reg[28]
-#define	mr29	fake_reg[29]
-#define	mr30	fake_reg[30]
-#define	mr31	fake_reg[31]
-#define	mr32	fake_reg[32]
-#define	mr33	fake_reg[33]
-#define	mr34	fake_reg[34]
-#define	mr35	fake_reg[35]
-#define	mr36	fake_reg[36]
+#define	mr10	MR_fake_reg[10]
+#define	mr11	MR_fake_reg[11]
+#define	mr12	MR_fake_reg[12]
+#define	mr13	MR_fake_reg[13]
+#define	mr14	MR_fake_reg[14]
+#define	mr15	MR_fake_reg[15]
+#define	mr16	MR_fake_reg[16]
+#define	mr17	MR_fake_reg[17]
+#define	mr18	MR_fake_reg[18]
+#define	mr19	MR_fake_reg[19]
+#define	mr20	MR_fake_reg[20]
+#define	mr21	MR_fake_reg[21]
+#define	mr22	MR_fake_reg[22]
+#define	mr23	MR_fake_reg[23]
+#define	mr24	MR_fake_reg[24]
+#define	mr25	MR_fake_reg[25]
+#define	mr26	MR_fake_reg[26]
+#define	mr27	MR_fake_reg[27]
+#define	mr28	MR_fake_reg[28]
+#define	mr29	MR_fake_reg[29]
+#define	mr30	MR_fake_reg[30]
+#define	mr31	MR_fake_reg[31]
+#define	mr32	MR_fake_reg[32]
+#define	mr33	MR_fake_reg[33]
+#define	mr34	MR_fake_reg[34]
+#define	mr35	MR_fake_reg[35]
+#define	mr36	MR_fake_reg[36]
+#define	mr37	MR_fake_reg[37]
 
 #endif /* not RS6000_REGS_H */
Index: runtime/machdeps/sparc_regs.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/machdeps/sparc_regs.h,v
retrieving revision 1.18
diff -u -r1.18 sparc_regs.h
--- sparc_regs.h	1997/07/27 15:09:12	1.18
+++ sparc_regs.h	1998/03/11 04:52:34
@@ -82,33 +82,34 @@
 #define restore_transient_regs_from_mem(save_area) \
 	restore_regs_from_mem(save_area)
 
-#define	mr10	fake_reg[10]
-#define	mr11	fake_reg[11]
-#define	mr12	fake_reg[12]
-#define	mr13	fake_reg[13]
-#define	mr14	fake_reg[14]
-#define	mr15	fake_reg[15]
-#define	mr16	fake_reg[16]
-#define	mr17	fake_reg[17]
-#define	mr18	fake_reg[18]
-#define	mr19	fake_reg[19]
-#define	mr20	fake_reg[20]
-#define	mr21	fake_reg[21]
-#define	mr22	fake_reg[22]
-#define	mr23	fake_reg[23]
-#define	mr24	fake_reg[24]
-#define	mr25	fake_reg[25]
-#define	mr26	fake_reg[26]
-#define	mr27	fake_reg[27]
-#define	mr28	fake_reg[28]
-#define	mr29	fake_reg[29]
-#define	mr30	fake_reg[30]
-#define	mr31	fake_reg[31]
-#define	mr32	fake_reg[32]
-#define	mr33	fake_reg[33]
-#define	mr34	fake_reg[34]
-#define	mr35	fake_reg[35]
-#define	mr36	fake_reg[36]
+#define	mr10	MR_fake_reg[10]
+#define	mr11	MR_fake_reg[11]
+#define	mr12	MR_fake_reg[12]
+#define	mr13	MR_fake_reg[13]
+#define	mr14	MR_fake_reg[14]
+#define	mr15	MR_fake_reg[15]
+#define	mr16	MR_fake_reg[16]
+#define	mr17	MR_fake_reg[17]
+#define	mr18	MR_fake_reg[18]
+#define	mr19	MR_fake_reg[19]
+#define	mr20	MR_fake_reg[20]
+#define	mr21	MR_fake_reg[21]
+#define	mr22	MR_fake_reg[22]
+#define	mr23	MR_fake_reg[23]
+#define	mr24	MR_fake_reg[24]
+#define	mr25	MR_fake_reg[25]
+#define	mr26	MR_fake_reg[26]
+#define	mr27	MR_fake_reg[27]
+#define	mr28	MR_fake_reg[28]
+#define	mr29	MR_fake_reg[29]
+#define	mr30	MR_fake_reg[30]
+#define	mr31	MR_fake_reg[31]
+#define	mr32	MR_fake_reg[32]
+#define	mr33	MR_fake_reg[33]
+#define	mr34	MR_fake_reg[34]
+#define	mr35	MR_fake_reg[35]
+#define	mr36	MR_fake_reg[36]
+#define	mr37	MR_fake_reg[37]
 
 #endif
 
%------------------------------------------------------------------------------%
#ifndef MERCURY_THREAD_H
#define MERCURY_THREAD_H

#ifdef	MR_THREAD_SAFE

#include <signal.h>	/* for sigset_t on the SPARC */
#include <pthread.h>
#include "mercury_std.h"

#if defined(__alpha__)
#define MR_MUTEX_ATTR	pthread_mutexattr_default
#define MR_COND_ATTR	pthread_condattr_default
#define MR_THREAD_ATTR	pthread_attr_default
#else
#define MR_MUTEX_ATTR	NULL
#define MR_COND_ATTR	NULL
#define MR_THREAD_ATTR	NULL
#endif

typedef	pthread_t	MercuryThread;
typedef pthread_key_t	MercuryThreadKey;
typedef pthread_mutex_t	MercuryLock;
typedef pthread_cond_t	MercuryCond;

#if 0
#define	MR_LOCK(lck, from)	pthread_mutex_lock((lck))
#define	MR_UNLOCK(lck, from)	pthread_mutex_unlock((lck))

#define	MR_SIGNAL(cnd)		pthread_cond_signal((cnd))
#define	MR_WAIT(cnd, mtx)	pthread_cond_wait((cnd), (mtx))
#else
void MR_mutex_lock(MercuryLock *lock, const char *from);
void MR_mutex_unlock(MercuryLock *lock, const char *from);
void MR_cond_signal(MercuryCond *cond);
void MR_cond_wait(MercuryCond *cond, MercuryLock *lock);

#define	MR_LOCK(lck, from)	MR_mutex_lock((lck), (from))
#define	MR_UNLOCK(lck, from)	MR_mutex_unlock((lck), (from))

#define	MR_SIGNAL(cnd)		MR_cond_signal((cnd))
#define	MR_WAIT(cnd, mtx)	MR_cond_wait((cnd), (mtx))
#endif

#if defined(__alpha__)
#define MR_GETSPECIFIC(key) 	({			\
		pthread_addr_t gstmp;			\
		pthread_getspecific((key), &gstmp);	\
		(void *) gstmp;				\
	})
#define	MR_KEY_CREATE	pthread_keycreate
#else
#define MR_GETSPECIFIC(key)	pthread_getspecific((key))
#define	MR_KEY_CREATE		pthread_key_create
#endif

MercuryThread	*create_thread(int x);
void		destroy_thread(void *eng);
extern bool	MR_exit_now;

#else

#define MR_LOCK(nothing, from)	do { } while (0)
#define MR_UNLOCK(nothing, from)	do { } while (0)

#define MR_SIGNAL(nothing)	do { } while (0)
#define MR_WAIT(no, thing)	do { } while (0)

#endif

void	*init_thread(void *);

#endif
%------------------------------------------------------------------------------%

/*
INIT mercury_scheduler_wrapper
ENDINIT
*/
/*
** Copyright (C) 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.
*/

#include "mercury_imp.h"
#include "mercury_regs.h"
#include "mercury_engine.h"
#include "mercury_memory.h"
#include "mercury_thread.h"

#include <stdio.h>
#include <errno.h>

#ifdef	MR_THREAD_SAFE
MercuryThreadKey MR_engine_base_key;
#endif

bool	MR_exit_now;

void *init_thread(void *unused);

Declare_entry(do_runnext);

#ifdef MR_THREAD_SAFE
MercuryThread *create_thread(int x)
{
	MercuryThread *thread;
	pthread_attr_t attrs;
	int err;

	thread = make(MercuryThread);
	pthread_attr_init(&attrs);
	err = pthread_create(thread, &attrs, init_thread, (void *) x);

#if 0
	fprintf(stderr, "pthread_create returned %d (errno = %d)\n",
		err, errno);
#endif

	if (err != 0)
		fatal_error("error creating thread");

	return thread;
}
#endif

void *init_thread(void *unused)
{
	MercuryEngine *eng;

	eng = create_engine();

#ifdef	MR_THREAD_SAFE
	pthread_setspecific(MR_engine_base_key, eng);
#endif

#ifdef MR_ENGINE_BASE_REGISTER
	restore_registers();

	MR_engine_base = eng;
	load_engine_regs(eng);
	load_context(eng->this_context);

	save_registers();
#else
	MR_engine_base = *eng;
	restore_registers();

	load_engine_regs(MR_engine_base);
	load_context(MR_engine_base.this_context);

	save_registers();
#endif

#ifdef	MR_THREAD_SAFE
	MR_ENGINE(owner_thread) = pthread_self();
#endif

	if (unused == 0) {
		call_engine(ENTRY(do_runnext));

		destroy_engine(eng);
	}

	return NULL;
}

#ifdef	MR_THREAD_SAFE
void destroy_thread(void *eng0)
{
	MercuryEngine *eng = eng0;
	destroy_engine(eng);
	pthread_exit(0);
}
#endif

#ifdef	MR_THREAD_SAFE
void MR_mutex_lock(MercuryLock *lock, const char *from)
{
	int err;

#if 0
	fprintf(stderr, "%d locking on %p (%s)\n", pthread_self(), lock, from);
#endif
	err = pthread_mutex_lock(lock);
	assert(err == 0);
}

void MR_mutex_unlock(MercuryLock *lock, const char *from)
{
	int err;

#if 0
	fprintf(stderr, "%d unlocking on %p (%s)\n", pthread_self(), lock, from);
#endif
	err = pthread_mutex_unlock(lock);
	assert(err == 0);
}

void MR_cond_signal(MercuryCond *cond)
{
	int err;

#ifdef 0
	fprintf(stderr, "%d signaling %p\n", pthread_self(), cond);
#endif
	err = pthread_cond_broadcast(cond);
	assert(err == 0);
}

void MR_cond_wait(MercuryCond *cond, MercuryLock *lock)
{
	int err;

#ifdef 0
	fprintf(stderr, "%d waiting on %p (%p)\n", pthread_self(), cond, lock);
#endif
	err = pthread_cond_wait(cond, lock);
	assert(err == 0);
}
#endif


Define_extern_entry(do_runnext);

BEGIN_MODULE(scheduler_module)
	init_entry(do_runnext);
BEGIN_CODE

Define_entry(do_runnext);
	runnext();

	fatal_error("Execution should never reach here.");

END_MODULE

void mercury_scheduler_wrapper(void); /* suppress gcc warning */
void mercury_scheduler_wrapper(void) {
	scheduler_module();
}




More information about the developers mailing list