changes to runtime

Thomas Charles CONWAY conway at cs.mu.oz.au
Fri Sep 19 15:52:32 AEST 1997


Hi

Here are my changes to the runtime. Note that they work with MR_PARALLEL
not defined, but if you define MR_PARALLEL, bad things may happen.

-- 
ZZ:wq!
^X^C
Thomas Conway               				      conway at cs.mu.oz.au
AD DEUM ET VINUM	  			      Every sword has two edges.

runtime/*.{c,h,mod}:
	A significant reorganization of the runtime.
	Stuff for supporting shared memory is gone. We're now going
	to assume that all the parallel "processes" are running in the
	one address space, using POSIX threads. Related to that, the
	stuff for forking processes, etc, is replaced with stuff for
	cloning threads.

	To support everything in the one address space, we have to make
	the engine "thread-safe". As a result we have a new structure
	MercuryEngine which contains all the bits of global state used
	by the engine, along with macros and functions for manipulating it.
	When MR_PARALLEL is *not* defined, everything (except for startup)
	behaves as it always did.

	If you try to define MR_PARALLEL BAD THINGS MAY HAPPEN. the stuff
	between MR_PARALLEL is untested, and my not even be syntactically
	valid.


cvs diff: Diffing .
Index: PORTABILITY
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/PORTABILITY,v
retrieving revision 1.3
diff -u -r1.3 PORTABILITY
--- PORTABILITY	1995/06/24 13:24:28	1.3
+++ PORTABILITY	1997/09/18 00:52:33
@@ -4,7 +4,7 @@
 Pointers are given two-bit tags - the code also assumes that the bottom
 two bits of pointers to words are zero, and fiddles with the bottom
 bits by casting pointers to integers and back again.
-(This can be turned off using mc's `--tags none' option.)
+(This can be turned off using mmc's `--tags none' option.)
 
 Various parts of the code are conditionalized to take advantage of
 GNU C's special features if they are available, and to use specific
Index: call.mod
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/call.mod,v
retrieving revision 1.30
diff -u -r1.30 call.mod
--- call.mod	1997/07/27 15:08:00	1.30
+++ call.mod	1997/09/16 02:28:18
@@ -43,7 +43,7 @@
 	push(num_in_args + num_extra_args); /* The number of input args */
 	push(succip);
 
-	save_registers();
+	save_arg_registers();
 
 	if (num_in_args < 3) {
 		for (i = 1; i <= num_extra_args; i++) {
@@ -59,7 +59,7 @@
 		virtual_reg(i) = field(0, closure, i+1); /* copy args */
 	}
 
-	restore_registers();
+	restore_arg_registers();
 
 	call((Code *) field(0, closure, 1), LABEL(det_closure_return),
 		LABEL(do_call_det_closure));
Index: conf.h.in
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/conf.h.in,v
retrieving revision 1.20
diff -u -r1.20 conf.h.in
--- conf.h.in	1997/08/28 18:20:55	1.20
+++ conf.h.in	1997/09/16 22:58:59
@@ -126,10 +126,11 @@
 #undef	SIGACTION_FIELD
 
 /*
-** PARALLEL: defined iff we are configuring for parallel execution.
+** MR_PARALLEL: defined iff we are configuring for parallel execution.
 ** (This is work in progress... parallel execution is not yet supported.)
+** XXX should be a separate grade really.
 */
-#undef	PARALLEL
+#undef	MR_PARALLEL
 
 /*
 ** The bytecode files represent floats in 64-bit IEEE format.
Index: context.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/context.h,v
retrieving revision 1.8
diff -u -r1.8 context.h
--- context.h	1997/09/05 23:19:52	1.8
+++ context.h	1997/09/18 01:11:17
@@ -7,37 +7,40 @@
 /*
 ** context.h - defines Mercury multithreading stuff.
 **
-** A Context is like a thread. It contains a detstack, a nondetstack, a trail,
-** the various pointers that refer to them, a succip, and a thread-
-** resumption continuation. Contexts are initally stored in a free-list.
-** When one is running, the Unix process that is executing it has a pointer
-** to its context structure `this_context'. When a context suspends, it
-** calls `save_context(context_ptr)' which copies the context from the
-** various registers and global variables into the structure refered to
-** by `context_ptr'. The context contains no rN or fN registers - all
-** registers are "context save" (by analogy to caller-save).
+** A Context is like a thread. It contains a detstack, a nondetstack, 
+** a trail, the various pointers that refer to them, a succip, and a
+** thread-resumption continuation. Contexts are initally stored in a
+** free-list. When one is running, the POSIX thread that is executing it
+** has a pointer to its context structure `this_context'. When a context
+** suspends, it calls `save_context(context_ptr)' which copies the context
+** from the various registers and global variables into the structure
+** refered to by `context_ptr'. The context contains no rN or fN registers -
+** all registers are "context save" (by analogy to caller-save).
 **
 ** When a new context is created information is passed to the new context
 ** on the stack. The top stackframe of the current context is copied to
 ** become the first det stackframe in the new process. (XXX this will need
 ** fixing eventually to include the nondet frame as well.)
 **
-** Threads can migrate transparently between multiple Unix processes.
-** This is implicit since all the state of the thread is allocated in
-** shared memory, and all the heaps are also in shared memory.
+** When using the conservative GC, all allocations are done from the single
+** memory pool managed by the collector. This unfortunately means that each
+** allocation will require a lock to be taken out which may be very expensive.
+** Using no GC or accurate GC, each POSIX thread has its own heap and solutions
+** heap. This will make GC somewhat harder, but means that allocation can be
+** done without locking which is believed to extremely important for good
+** performance.
 **
-** Each Unix process has its own heap and solutions heap (both allocated
-** in shared memory). This makes GC harder, but enables heap allocation
-** to be done without locking.
-** Each context has a copy of the heap pointer that is taken when it is
-** switched out. If the Unix process' heap pointer is the same as the
-** copied one when the context is switched back in, then it is safe for
-** the context to do heap reclamation on failure.
+** Because a context may migrate from one thread to another, reclaiming
+** heap on failure requires some special handling. Each context has a copy of
+** the heap pointer that is taken when it is switched out. If the thread's
+** heap pointer is the same as the copied one when the context is switched
+** back in, then it is safe for the context to do heap reclamation on failure.
+** If the thread's heap pointer is not the same, then the lowest point to
+** which the heap may be truncated is dictated by the thread's heap pointer
+** at the time when the context was swapped in.
 **
-** If PARALLEL is not defined, then everything gets executed within a
-** single Unix process. No locking is required. No shared memory is
-** required. Since there is only one process, no signalling is needed
-** to wake suspended processes.
+** If MR_PARALLEL is not defined, then everything gets executed within a
+** single thread.
 */
 
 #ifndef CONTEXT_H
@@ -45,12 +48,15 @@
 
 #include "regs.h"		/* for hp. Must come before system headers. */
 
-#include <sys/types.h>		/* for pid_t */
+#ifdef	MR_PARALLEL
+#include <semaphore.h>		/* for sem_t */
+#include <pthread.h>		/* for various pthread stuff */
+#endif
 
 #include "mercury_types.h"	/* for Word */
 #include "mercury_trail.h"	/* for MR_TrailEntry */
 #include "memory.h"		/* for MemoryZone */
-#include "spinlock.h"		/* for SpinLock */
+#include "spinlock.h"		/* for MR_Mutex */
 #include "goto.h"		/* for GOTO() */
 
 /*
@@ -59,20 +65,11 @@
 ** Ultimately this should be configurable through the
 ** MERCURY_OPTIONS environment variable.
 */
-#ifdef	PARALLEL
-extern unsigned numprocs;
+#ifdef	MR_PARALLEL
+extern unsigned numthreads;
 #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
@@ -137,13 +134,27 @@
 ** need to be reinitialized, but have space allocated to
 ** them. (see comments in memory.h about reset_zone())
 */
-extern	Context **free_context_list_ptr;
+extern	Context *free_context_list_ptr;
+
+/*
+** a pointer to a word used for the spinlock on the free
+** context list
+*/
+extern	MR_Mutex *free_context_list_lock;
 
 /*
 ** the runqueue is a linked list of contexts that are
 ** runnable.
 */
-extern	Context **runqueue_ptr;
+extern	Context *runqueue_ptr;
+
+/*
+** If we have parallelism enabled, we need a global semaphore for
+** the runqueue.
+*/
+#ifdef	MR_PARALLEL
+extern sem_t	mr_runqueue_sem;
+#endif
 
 /*
 ** this_context is a pointer to the currently executing
@@ -151,36 +162,31 @@
 ** 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;
+#ifndef MR_PARALLEL
+extern	Context *mr_this_context;
+#else
+#define	mr_this_context	(mr_engine_base->e_this_context)
+#endif
 
 /*
-** a pointer to a word used for the spinlock on the free
-** context list
+** init_context_state() initializes the global state for managing
+** contexts.
 */
-extern	SpinLock *free_context_list_lock;
+void	init_context_state(void);
 
 /*
-** init_processes() forks new process (if necessary), and
-** initializes the data-structures for managing the interactions
-** between them.
+** init_main_context() initializes a context structure for main to
+** run in.
 */
-void	init_processes(void);
+void	init_main_context(void);
 
 /*
-** shutdown_processes() sends a signal to the other processes
+** shutdown_threads() sends a signal to the other threads
 ** 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.
-*/
-void	init_process_context(void);
+#ifdef	MR_PARALLEL
+void	shutdown_threads(void);
+#endif
 
 /*
 ** new_context() allocates and initializes a new context
@@ -197,40 +203,27 @@
 
 /*
 ** flounder() aborts with a runtime error message. It is called if
-** the runqueue becomes empty and none of the running processes are
+** the runqueue becomes empty and none of the running threads are
 ** working - ie the computation has floundered.
 */
 void	flounder(void);
 
 /*
-** procid[N] is the process id of the Nth process.
-** procid[my_procnum] == getpid() == my_procid.
+** threadid[N] is the thread id of the Nth threads.
+** threadid[my_threadnum] == pthread_self() == my_threadid.
 */
-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.)
-*/
-typedef Word		AtomicBool;
-extern	AtomicBool	*procwaiting;
+#ifdef MR_PARALLEL
+extern	pthread_t	*threadid;
+#endif
 
 /*
-** my_procnum is the number of the current process.
-** my_procnum == 0 is the original parent process.
+** my_threadnum is the number of the current thread.
+** my_threadnum == 0 is the original parent thread.
 */
-extern	int	my_procnum;
-extern	pid_t	my_procid;
+#ifdef	MR_PARALLEL
+#define	my_threadnum	(mr_engine_base->e_thread_num)
+#define my_threadid	(mr_engine_base->e_thread_id)
+#endif
 
 /*
 ** The minimum value of hp to which the current context
@@ -305,7 +298,7 @@
 ** and we are now contiguous with our older data, so this algorithm will lead
 ** to holes in the heap, though GC will reclaim these.
 **
-** If hp == context_hp then no other process has allocated any heap since we
+** If hp == context_hp then no other thread has allocated any heap since we
 ** were last scheduled, so we can proceed as if we had not stopped, and the
 ** furthest back that we can backtrack is the same as it was last time we
 ** were executing.
@@ -383,9 +376,9 @@
 /*
 ** 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_LOCK] is a MR_Mutex
 **	sync_term[SYNC_TERM_COUNTER] is a counter for the number of
-**			processes that need to synchronize before the
+**			threads 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
Index: context.mod
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/context.mod,v
retrieving revision 1.10
diff -u -r1.10 context.mod
--- context.mod	1997/09/05 23:19:54	1.10
+++ context.mod	1997/09/18 01:24:28
@@ -10,133 +10,98 @@
 
 #include <stdio.h>
 #include <unistd.h>		/* for getpid() and fork() */
-#ifdef PARALLEL
-#include <signal.h>
+#ifdef MR_PARALLEL
+#include <pthread.h>
+#include <semaphore.h>
 #endif
 
 #include "context.h"
 #include "engine.h"	/* for `memdebug' */
 
-#ifdef	PARALLEL
-unsigned numprocs = 1;
+#ifdef	MR_PARALLEL
+unsigned numthreads = 1;
 #endif
 
-#ifdef	PARALLEL
-pid_t	*procid;
-AtomicBool *procwaiting;
+#ifdef	MR_PARALLEL
+pthread_d	my_thread_id;
+int		my_thread_num;
+Word		*min_heap_reclamation_point;
+#endif
+
+/*
+** For sequential execution, this_context is a global pointer to the current
+** Context structure. For parallel execution, this_context is a macro that
+** references the e_this_context field of the MercuryEngine structure.
+*/
+#ifndef	MR_PARALLEL
+Context	*this_context;
+#else
+#define	this_context	(mr_engine_base->e_this_context)
 #endif
-int	my_procnum;
-pid_t	my_procid;
-Word	*min_heap_reclamation_point;
 
-Context	*this_context;
-Context	**runqueue_ptr;
-Context	**free_context_list_ptr;
-SpinLock *runqueue_lock;
-SpinLock *free_context_list_lock;
+/*
+** We maintain a list of allocated, but unused Context structures.
+** During parallel execution we need a lock on it.
+*/
+Context	*free_context_list;
+#ifdef	MR_PARALLEL
+MR_Mutex *free_context_list_lock;
+#endif
+
+/*
+** The runqueue is a linked list of runable Context structures. 
+** If the list becomes empty and all threads are suspended, then we
+** abort, reporting that computation floundered.
+** If we are running in parallel, then we use a semaphore (whoes value
+** reflects the number of runable contexts in the queue) to wake and
+** suspend threads.
+*/
+Context	*runqueue;
+#ifdef	MR_PARALLEL
+MR_Sem *runqueue_sem;
+#endif
 
+/* XXX - need defs for MR_PARALLEL */
 Context	*do_schedule_cptr;
 Code	*do_schedule_resume;
 Word     *do_join_and_terminate_sync_term;
 Word     *do_join_and_continue_sync_term;
 Code     *do_join_and_continue_where_to;
 
-static void init_free_context_list(void);
-
-void 
-init_processes(void)
+void
+init_context_state(void)
 {
-	int i;
-	pid_t pid;
+	free_context_list = NULL;
+	runqueue = NULL;
+#ifdef	MR_PARALLEL
+	free_context_list_lock = mr_create_lock();
+	runqueue_sem = mr_create_sempahore();
+#endif
 
-	my_procnum = 0;
-	my_procid = getpid();
+}
 
-	runqueue_lock = allocate_lock();
-	runqueue_ptr = allocate_object(Context *);
-	*runqueue_ptr = NULL;
-
-#ifdef	PARALLEL
-	procid = allocate_array(pid_t, numprocs);
-	procwaiting = allocate_array(AtomicBool, numprocs);
-	procid[0] = my_procid;
-	procwaiting[0] = FALSE;
-
-	for (i = 1; i < numprocs; i++) {
-		if ((pid = fork()) < 0) {
-			fatal_error("failed to fork()");
-		}
-		if (pid == 0) { /* child */
-			my_procnum = i;
-			procid[i] = my_procid = getpid();
-			procwaiting[i] = FALSE;
-			return;
-		}
-	}
-#endif
+void
+init_main_context(void)
+{
+	this_context = new_context();
+	restore_transient_registers();
+	load_context(this_context);
+	save_transient_registers();
 
+	if (memdebug) debug_memory();
 }
 
+#ifdef MR_PARALLEL
 void
-shutdown_processes(void)
+shutdown_threads(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 */
-		init_free_context_list();
-		this_context = new_context();
-			/* load the registers so we don't clobber hp */
-		restore_transient_registers();
-		load_context(this_context);
-		save_transient_registers();
-
-		if (memdebug) debug_memory();
-	}
-}
-
-static void 
-init_free_context_list(void)
-{
-	int i;
-	Context *tmp;
-
-	free_context_list_lock = allocate_lock();
-	free_context_list_ptr = allocate_object(Context *);
-	*free_context_list_ptr = allocate_array(Context, INITIAL_NUM_CONTEXTS);
-	tmp = *free_context_list_ptr;
-	for (i = 0; i < INITIAL_NUM_CONTEXTS; i++) {
-		if (i != INITIAL_NUM_CONTEXTS - 1) {
-			tmp[i].next = &(tmp[i+1]);
-		} else {
-			tmp[i].next = NULL;
-		}
-		tmp[i].resume = NULL;
-		tmp[i].context_succip = NULL;
-		tmp[i].detstack_zone = NULL;
-		tmp[i].context_sp = NULL;
-		tmp[i].nondetstack_zone = NULL;
-		tmp[i].context_curfr = NULL;
-		tmp[i].context_maxfr = NULL;
-	}
 }
+#endif
 
 Context *
 new_context(void)
@@ -145,12 +110,12 @@
 
 	get_lock(free_context_list_lock);
 
-	MR_assert(free_context_list_ptr != NULL);
-	if (*free_context_list_ptr == NULL) {
-		fatal_error("no free contexts");
+	MR_assert(free_context_list != NULL);
+	if (free_context_list == NULL) {
+		c = allocate_object(Context);
 	} else {
-		c = *free_context_list_ptr;
-		*free_context_list_ptr = c->next;
+		c = free_context_list;
+		free_context_list = c->next;
 	}
 	release_lock(free_context_list_lock);
 
@@ -171,7 +136,7 @@
 		reset_zone(c->nondetstack_zone);
 	} else {
 		c->nondetstack_zone = create_zone("nondetstack", 0,
-			nondstack_size, next_offset(), nondstack_zone_size,
+			nondetstack_size, next_offset(), nondetstack_zone_size,
 			default_handler);
 	}
 	c->context_maxfr = c->nondetstack_zone->min;
@@ -202,9 +167,9 @@
 delete_context(Context *c)
 {
 	get_lock(free_context_list_lock);
-	MR_assert(free_context_list_ptr != NULL);
-	c->next = *free_context_list_ptr;
-	*free_context_list_ptr = c;
+	MR_assert(free_context_list != NULL);
+	c->next = free_context_list;
+	free_context_list = c;
 	release_lock(free_context_list_lock);
 }
 
@@ -224,7 +189,7 @@
 	*/
 do_runnext:
 	while(1) {
-#ifdef	PARALLEL
+#ifdef	MR_PARALLEL
 		/* If we're running in parallel, then we need to
 		** do some signal magic in order to avoid a race-
 		** condition if we have to suspend, waiting for
@@ -257,11 +222,11 @@
 		sigprocmask(SIG_BLOCK, &newset, &oldset);
 #endif
 		get_lock(runqueue_lock);
-		if (*runqueue_ptr != NULL) {
-			this_context = *runqueue_ptr;
-			*runqueue_ptr = (*runqueue_ptr)->next;
+		if (runqueue != NULL) {
+			this_context = runqueue;
+			runqueue = runqueue->next;
 			release_lock(runqueue_lock);
-#ifdef	PARALLEL
+#ifdef	MR_PARALLEL
 			/* restore the original set of signals */
 			sigprocmask(SIG_SETMASK, &oldset, NULL);
 #endif
@@ -270,7 +235,7 @@
 		}
 		else
 		{
-#ifdef	PARALLEL
+#ifdef	MR_PARALLEL
 			int i;
 			bool is_runnable;
 
@@ -295,7 +260,7 @@
 			
 #endif
 			release_lock(runqueue_lock);
-#ifdef	PARALLEL
+#ifdef	MR_PARALLEL
 			sigsuspend(&emptyset);
 			procwaiting[my_procnum] = FALSE;
 #else
@@ -317,10 +282,10 @@
 	Context *old;
 
 	get_lock(runqueue_lock);
-	old = *runqueue_ptr;
-	do_schedule_cptr->next = *runqueue_ptr;
-	*runqueue_ptr = do_schedule_cptr;
-#ifdef	PARALLEL
+	old = runqueue;
+	do_schedule_cptr->next = runqueue;
+	runqueue = do_schedule_cptr;
+#ifdef	MR_PARALLEL
 	/* Check to see if we need to signal a sleeping process */
 	if (old == NULL) {
 		int i;
@@ -350,17 +315,17 @@
 
 	sync_term = do_join_and_terminate_sync_term;
 
-	get_lock((SpinLock *)&sync_term[SYNC_TERM_LOCK]);
+	get_lock((MR_Mutex *)&sync_term[SYNC_TERM_LOCK]);
 	if (--(sync_term[SYNC_TERM_COUNTER]) == 0) {
 		MR_assert(sync_term[SYNC_TERM_PARENT] != NULL);
-		release_lock((SpinLock *)&sync_term[SYNC_TERM_LOCK]);
+		release_lock((MR_Mutex *)&sync_term[SYNC_TERM_LOCK]);
 		ctxt = (Context *) sync_term[SYNC_TERM_PARENT];
 		delete_context(this_context);
 		this_context = ctxt;
 		load_context(this_context);
 		GOTO(this_context->resume);
 	} else {
-		release_lock((SpinLock *)&sync_term[SYNC_TERM_LOCK]);
+		release_lock((MR_Mutex *)&sync_term[SYNC_TERM_LOCK]);
 		delete_context(this_context);
 		runnext();
 	}
@@ -380,16 +345,16 @@
 
 	sync_term = do_join_and_continue_sync_term;
 
-	get_lock((SpinLock *)&sync_term[SYNC_TERM_LOCK]);
+	get_lock((MR_Mutex *)&sync_term[SYNC_TERM_LOCK]);
 	if (--(sync_term[SYNC_TERM_COUNTER]) == 0) {
 		MR_assert(sync_term[SYNC_TERM_PARENT] == NULL);
-		release_lock((SpinLock *)&sync_term[SYNC_TERM_LOCK]);
+		release_lock((MR_Mutex *)&sync_term[SYNC_TERM_LOCK]);
 		GOTO(do_join_and_continue_where_to);
 	} else {
 		save_context(this_context);
 		this_context->resume = do_join_and_continue_where_to;
 		sync_term[SYNC_TERM_PARENT] = (Word) this_context;
-		release_lock((SpinLock *)&sync_term[SYNC_TERM_LOCK]);
+		release_lock((MR_Mutex *)&sync_term[SYNC_TERM_LOCK]);
 		runnext();
 	}
 }
Index: debug.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/debug.h,v
retrieving revision 1.11
diff -u -r1.11 debug.h
--- debug.h	1997/07/27 15:08:08	1.11
+++ debug.h	1997/09/12 02:37:18
@@ -92,25 +92,25 @@
 	IF (progdebug, (save_transient_registers(), printregs(msg)))
 
 #define	debugmkframe() \
-	IF (nondstackdebug, (save_transient_registers(), mkframe_msg()))
+	IF (nondetstackdebug, (save_transient_registers(), mkframe_msg()))
 
 #define	debugframe(msg)	 \
 	IF (progdebug, (save_transient_registers(), printframe(msg)))
 
 #define	debugmodframe() \
-	IF (nondstackdebug, (save_transient_registers(), modframe_msg()))
+	IF (nondetstackdebug, (save_transient_registers(), modframe_msg()))
 
 #define	debugsucceed() \
-	IF (nondstackdebug, (save_transient_registers(), succeed_msg()))
+	IF (nondetstackdebug, (save_transient_registers(), succeed_msg()))
 
 #define	debugsucceeddiscard() \
-	IF (nondstackdebug, (save_transient_registers(), succeeddiscard_msg()))
+	IF (nondetstackdebug, (save_transient_registers(), succeeddiscard_msg()))
 
 #define	debugfail() \
-	IF (nondstackdebug, (save_transient_registers(), fail_msg()))
+	IF (nondetstackdebug, (save_transient_registers(), fail_msg()))
 
 #define	debugredo() \
-	IF (nondstackdebug, (save_transient_registers(), redo_msg()))
+	IF (nondetstackdebug, (save_transient_registers(), redo_msg()))
 
 #define	debugcall(proc, succ_cont) \
 	IF (calldebug, (save_transient_registers(), call_msg(proc, succ_cont)))
Index: engine.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/engine.h,v
retrieving revision 1.14
diff -u -r1.14 engine.h
--- engine.h	1997/09/05 23:19:55	1.14
+++ engine.h	1997/09/18 01:35:23
@@ -16,6 +16,12 @@
 #include "std.h"		/* for `bool' */
 #include "mercury_types.h"	/* for `Code *' */
 #include "goto.h"		/* for `Define_entry()' */
+#include "memory.h"		/* for `MemoryZone' */
+#include "context.h"		/* for `Context' */
+
+#ifdef	MR_PARALLEL
+#include <pthread.h>		/* for the various pthread bits */
+#endif
 
 #define	PROGFLAG	0
 #define	GOTOFLAG	1
@@ -36,7 +42,7 @@
 #define	calldebug	debugflag[CALLFLAG]
 #define	heapdebug	debugflag[HEAPFLAG]
 #define	detstackdebug	debugflag[DETSTACKFLAG]
-#define	nondstackdebug	debugflag[NONDSTACKFLAG]
+#define	nondetstackdebug debugflag[NONDSTACKFLAG]
 #define	finaldebug	debugflag[FINALFLAG]
 #define	memdebug	debugflag[MEMFLAG]
 #define	sregdebug	debugflag[SREGFLAG]
@@ -45,10 +51,120 @@
 
 extern	bool	debugflag[];
 
-extern	void	init_engine(void);
-extern	void	call_engine(Code *entry_point);
-extern	void	terminate_engine(void);
-extern	void	dump_prev_locations(void);
+/*
+** A MercuryEngine structure contains the data structures necessary for
+** executing Mercury programs. It contains the following elements:
+**	- a fake reg array for storing all the virtual machine registers
+**	- MemoryZone pointers for the detstack, nondetstack, heap and trail
+**	- any other state necessary for the engine
+**
+** The function `create_engine' returns a pointer to a MercuryEngine structure.
+** The argument determines whether a detstack, nondetstack and trail are
+** allocated. If the engine structure is to be used by a child thread for
+** executing parallel code, then there is no need to allocate stacks, since
+** they will be provided by the context structure for the parallel goal.
+*/
+typedef struct MERCURY_ENGINE {
+	Word		e_fake_reg[MAX_FAKE_REG];
+	MemoryZone	*e_detstack_zone;
+	MemoryZone	*e_nondetstack_zone;
+#ifdef	MR_USE_TRAIL
+	MemoryZone	*e_trail_zone;
+#endif
+#ifndef CONSERVATIVE_GC
+	MemoryZone	*e_heap_zone;
+	MemoryZone	*e_solutions_heap_zone;
+#endif
+#ifndef SPEED
+	MemoryZone	*e_dumpstack_zone;
+	int		*e_dumpindex;
+#endif
+	Context		*e_this_context;
+#ifdef	MR_PARALLEL
+	int		e_thread_num;
+	pthread_t	e_thread_id;
+#endif
+} MercuryEngine;
+
+#ifndef	MR_PARALLEL
+
+#ifdef	MR_USE_TRAIL
+#define	load_trail(engine_ptr)		do {				\
+		trail_zone	= (engine_ptr)->e_trail_zone;		\
+	} while (0)
+
+#define save_trail(engine_ptr)		do {				\
+		(engine_ptr)->e_trail_zone	= trail_zone;		\
+	} while (0)
+#else
+#define load_trail(unused)		do { } while (0)
+#define save_trail(unused)		do { } while (0)
+#endif
+
+#ifndef	CONSERVATIVE_GC
+#define	load_heaps(engine_ptr)		do {				\
+		heap_zone	= (engine_ptr)->e_heap_zone;		\
+		solutions_heap_zone = (engine_ptr)->e_solutions_heap_zone; \
+	} while (0)
+
+#define	save_heaps(engine_ptr)		do {				\
+		(engine_ptr)->e_heap_zone	= heap_zone;		\
+		(engine_ptr)->e_solutions_heap_zone = solutions_heap_zone; \
+	} while (0)
+#else
+#define load_heaps(unused)		do { } while (0)
+#define save_heaps(unused)		do { } while (0)
+#endif
+
+#ifndef	SPEED
+#define	load_dumpstacks(engine_ptr)	do {				\
+		dumpstack_zone	= (engine_ptr)->e_dumpstack_zone;	\
+		dumpindex	= (engine_ptr)->e_dumpindex;		\
+	} while (0)
+
+#define	save_dumpstacks(engine_ptr)	do {				\
+		(engine_ptr)->e_dumpstack_zone	= dumpstack_zone;	\
+		(engine_ptr)->e_dumpindex	= dumpindex;		\
+	} while (0)
+#else
+#define load_dumpstacks(unused)		do { } while (0)
+#define save_dumpstacks(unused)		do { } while (0)
+#endif
+
+#define load_engine(engine_ptr)		do { \
+		fake_reg	= (engine_ptr)->e_fake_reg;		\
+		detstack_zone	= (engine_ptr)->e_detstack_zone;	\
+		nondetstack_zone= (engine_ptr)->e_nondetstack_zone;	\
+		load_trail((engine_ptr));				\
+		load_heaps((engine_ptr));				\
+		load_dumpstacks((engine_ptr));				\
+	} while (0)
+
+#define save_engine(engine_ptr)		do { \
+		(engine_ptr)->e_fake_reg	= fake_reg;		\
+		(engine_ptr)->e_detstack_zone	= detstack_zone;	\
+		(engine_ptr)->e_nondetstack_zone= nondetstack_zone;	\
+		save_trail((engine_ptr));				\
+		save_heaps((engine_ptr));				\
+		save_dumpstacks((engine_ptr));				\
+	} while (0)
+
+#else
+
+#define	load_engine(engine_ptr)		\
+		pthread_setspecific(mr_engine_base_key, (void *) (engine_ptr))
+
+#define save_engine(engine_ptr)		\
+		pthread_getspecific(mr_engine_base_key, (void *) (engine_ptr))
+
+#endif
+
+extern	MercuryEngine	*create_engine(void);
+
+extern	void		init_engine(void);
+extern	void		call_engine(Code *entry_point);
+extern	void		terminate_engine(void);
+extern	void		dump_prev_locations(void);
 
 Declare_entry(do_redo);
 Declare_entry(do_fail);
@@ -56,5 +172,10 @@
 Declare_entry(do_reset_framevar0_fail);
 Declare_entry(do_succeed);
 Declare_entry(do_not_reached);
+
+#ifdef	MR_PARALLEL
+extern pthread_key_t	 mr_engine_base_key;
+extern pthread_t	*mr_threads;
+#endif
 
 #endif /* not ENGINE_H */
Index: engine.mod
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/engine.mod,v
retrieving revision 1.43
diff -u -r1.43 engine.mod
--- engine.mod	1997/09/05 23:19:57	1.43
+++ engine.mod	1997/09/18 01:36:07
@@ -29,6 +29,16 @@
 static	Code	*engine_init_registers(void);
 #endif
 
+#ifdef	MR_PARALLEL
+static	void	init_threads(void);
+static	void	start_thread(MercuryEngine *e);
+pthread_t	*mr_threads;
+pthread_key_t	mr_engine_base_key;
+MercuryEngine	*mr_engine_bases;
+#else
+MercuryEngine	*mr_engine_base;
+#endif
+
 bool	debugflag[MAXFLAG];
 
 static jmp_buf *engine_jmp_buf;
@@ -55,24 +65,97 @@
 void 
 init_engine(void)
 {
+	MercuryEngine	*e;
+#ifdef	MR_PARALLEL
+	int	err;
+#endif
+
 	init_memory();
+	init_context_state();
 
 #ifndef USE_GCC_NONLOCAL_GOTOS
 	make_label("engine_done", LABEL(engine_done));
 #endif
 
-	init_processes();
-	init_process_context();
+#ifdef MR_PARALLEL
+	pthread_key_create(&mr_engine_base_key, mr_engine_base_destroy);
 
-	if (my_procnum == 0) {
-		return;
-	} else {
-		call_engine(ENTRY(do_runnext));
-		/* not reached */
-		MR_assert(FALSE);
+	mr_engine_bases = allocate_array(MercuryEngine, numthreads);
+	mr_threads = allocate_array(pthread_t, numthreads);
+
+	mr_engine_bases[0] = create_engine();
+	mr_threads[0] = pthread_self();
+
+	pthread_setspecific(mr_engine_base_key, e);
+
+	init_threads();
+#else
+	mr_engine_base = create_engine();
+	load_engine(mr_engine_base);
+#endif
+
+	init_main_context();
+}
+
+/*---------------------------------------------------------------------------*/
+#ifdef	MR_PARALLEL
+
+static void
+init_threads(void)
+{
+	int n, err;
+
+	for (n = 1; n < numprocs; n++)
+	{
+		mr_engine_bases[n] = create_engine();
+		err = pthread_create(mr_threads+n, MR_THREAD_ATTRS,
+			start_thread, (void *) mr_engine_bases[n]);
+		if (err != 0)
+		{
+			fatal_error("unable to create thread.\n");
+		}
 	}
 }
 
+MR_THREAD_RETURN_T start_thread(void *v)
+{
+	MercuryEngine *e;
+
+	e = (MercuryEngine *) v;
+	pthread_setspecific(mr_engine_base_key, e);
+	call_engine(ENTRY(do_runnext));
+	/* not reached */
+	MR_assert(FALSE);
+}
+
+#endif
+/*---------------------------------------------------------------------------*/
+
+MercuryEngine *create_engine(void)
+{
+	MercuryEngine *e;
+
+	e = allocate_object(MercuryEngine);
+	if (!e)
+		fatal_error("failed to allocate MercuryEngine.\n");
+
+#ifdef	CONSERVATIVE_GC
+	GC_is_visible(e->e_fake_reg);
+#endif
+
+	e->e_detstack_zone = NULL;
+	e->e_nondetstack_zone = NULL;
+#ifdef MR_USE_TRAIL
+	e->e_tail_zone = NULL;
+#endif
+#ifndef CONSERVATIVE_GC
+	e->e_heap_zone = create_heap();
+	e->e_solutions_heap_zone = create_solutions_heap();
+#endif
+
+	return e;
+}
+
 /*---------------------------------------------------------------------------*/
 
 /*
@@ -391,7 +474,9 @@
 	** that will happen automatically on process exit anyway.
 	*/
 
-	shutdown_processes();
+#ifdef	MR_PARALLEL
+	shutdown_threads();
+#endif
 }
 
 /*---------------------------------------------------------------------------*/
Index: memory.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/memory.c,v
retrieving revision 1.77
diff -u -r1.77 memory.c
--- memory.c	1997/09/05 23:20:01	1.77
+++ memory.c	1997/09/18 03:37:47
@@ -17,7 +17,7 @@
 **	the register array 
 **	the bottom of the heap 
 **	the bottom of the detstack 
-**	the bottom of the nondstack 
+**	the bottom of the nondetstack 
 **
 ** all start at different offsets from multiples of the primary cache size.
 ** This should reduce cache conflicts (especially for small programs).
@@ -167,27 +167,34 @@
 
 static	void	setup_signal(void);
 
-Word	fake_reg[MAX_FAKE_REG];
+#ifndef MR_PARALLEL
+  Word	*fake_reg;
+#endif
 
 Word	virtual_reg_map[MAX_REAL_REG] = VIRTUAL_REG_MAP_BODY;
 
+#ifndef	MR_PARALLEL
 unsigned long	num_uses[MAX_RN];
-
-MemoryZone *zone_table;
+#endif
 
 MemoryZone *used_memory_zones;
 MemoryZone *free_memory_zones;
 
-MemoryZone *detstack_zone;
-MemoryZone *nondetstack_zone;
+#ifndef	MR_PARALLEL
+  MemoryZone *detstack_zone;
+  MemoryZone *nondetstack_zone;
+#ifdef	MR_USE_TRAIL
+    MemoryZone *trail_zone;
+#endif
 #ifndef CONSERVATIVE_GC
-  MemoryZone *heap_zone;
-  MemoryZone *solutions_heap_zone;
-  Word       *solutions_heap_pointer;
+    MemoryZone *heap_zone;
+    MemoryZone *solutions_heap_zone;
+    Word       *solutions_heap_pointer;
 #endif
 #ifndef	SPEED
-  MemoryZone *dumpstack_zone;
-  int	dumpindex;
+    MemoryZone *dumpstack_zone;
+    int	dumpindex;
+#endif
 #endif
 
 static	size_t		unit;
@@ -208,10 +215,9 @@
 
 static	size_t		*offset_vector;
 static	int		*offset_counter;
-static	SpinLock	*offset_lock;
+static	MR_Mutex	*offset_lock;
 size_t	next_offset(void);
 
-static void init_memory_arena(void);
 static void init_zones(void);
 
 void 
@@ -240,8 +246,8 @@
 
 	detstack_size       = round_up(detstack_size * 1024, unit);
 	detstack_zone_size  = round_up(detstack_zone_size * 1024, unit);
-	nondstack_size      = round_up(nondstack_size * 1024, unit);
-	nondstack_zone_size = round_up(nondstack_zone_size * 1024, unit);
+	nondetstack_size      = round_up(nondetstack_size * 1024, unit);
+	nondetstack_zone_size = round_up(nondetstack_zone_size * 1024, unit);
 
 #ifdef MR_USE_TRAIL
 	trail_size       = round_up(trail_size * 1024, unit);
@@ -269,8 +275,8 @@
 		detstack_zone_size = unit;
 	}
 
-	if (nondstack_zone_size >= nondstack_size) {
-		nondstack_zone_size = unit;
+	if (nondetstack_zone_size >= nondetstack_size) {
+		nondetstack_zone_size = unit;
 	}
 
 #ifdef MR_USE_TRAIL
@@ -279,7 +285,6 @@
 	}
 #endif
 
-	init_memory_arena();
 	init_zones();
 	setup_signal();
 	if (memdebug) debug_memory();
@@ -330,79 +335,21 @@
 	}
 }
 
-/*
-** 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()
 {
 	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;
-		}
-	}
+	free_memory_zones = NULL;
 
 	offset_counter = allocate_object(int);
 	*offset_counter = 0;
 
 	offset_vector = allocate_array(size_t, CACHE_SLICES - 1);
 
-	fake_reg_offset = (Unsigned) fake_reg % pcache_size;
-
 	for (i = 0; i < CACHE_SLICES - 1; i++) {
-		offset_vector[i] =
-			(fake_reg_offset + pcache_size / CACHE_SLICES)
-			% pcache_size;
+		offset_vector[i] = (pcache_size / CACHE_SLICES) % pcache_size;
 	}
 } /* end init_zones() */
 
@@ -438,6 +385,42 @@
 #endif
 } /* end init_heap() */
 
+
+MemoryZone *create_detstack(void)
+{
+	return create_zone("detstack", 0, detstack_size, next_offset(),
+			detstack_zone_size, default_handler);
+}
+
+MemoryZone *create_nondetstack(void)
+{
+	return create_zone("nondetstack", 0, nondetstack_size, next_offset(),
+			nondetstack_zone_size, default_handler);
+}
+
+#ifdef MR_USING_TRAIL
+MemoryZone *create_trail(void)
+{
+	return create_zone("trail", 0, trail_size, next_offset(),
+			trail_zone_size, default_handler);
+}
+#endif
+
+#ifndef CONSERVATIVE_GC
+MemoryZone *create_heap(void)
+{
+	return create_zone("heap", 1, heap_size, next_offset(), heap_zone_size,
+				default_handler);
+}
+
+MemoryZone *create_solutions_heap(void)
+{
+	return create_zone("solutions_heap", 1, solutions_heap_size,
+			next_offset(), solutions_heap_zone_size,
+			default_handler);
+}
+#endif
+
 MemoryZone *
 get_zone(void)
 {
@@ -449,9 +432,10 @@
 	*/
 	zone = free_memory_zones;
 	if (zone == NULL) {
-		fatal_error("no more memory zones");
+		zone = allocate_object(MemoryZone);
+	} else {
+		free_memory_zones = free_memory_zones->next;
 	}
-	free_memory_zones = free_memory_zones->next;
 
 	zone->next = used_memory_zones;
 	used_memory_zones = zone;
@@ -533,11 +517,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];
Index: memory.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/memory.h,v
retrieving revision 1.28
diff -u -r1.28 memory.h
--- memory.h	1997/09/05 23:20:04	1.28
+++ memory.h	1997/09/18 01:37:29
@@ -27,7 +27,11 @@
 
 /* these cannot be changed without lots of modifications elsewhere */
 #define MAX_REAL_REG 32		/* r1 .. r32 */
+#ifndef	MR_USE_TRAIL
 #define NUM_SPECIAL_REG 5	/* succip, sp, hp, maxfr, curfr */
+#else
+#define NUM_SPECIAL_REG 7	/* as above + trail, ticket */
+#endif
 
 /* this can be changed at will, including by -D options to the C compiler */
 #ifndef MAX_VIRTUAL_REG
@@ -40,13 +44,23 @@
 				/* 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];
+#ifndef	MR_PARALLEL
+extern	Word	*fake_reg;
+#else
+#define	fake_reg	(mr_engine_base->e_fake_reg)
+#endif
 
 /* used to lookup the fake_reg for a given real reg */
 extern	Word	virtual_reg_map[MAX_REAL_REG];
 
 /* used for counting register usage */
-extern	unsigned long 	num_uses[MAX_RN];
+#if	defined(MEASURE_REGISTER_USAGE)
+  #ifndef MR_PARALLEL
+    extern	unsigned long 	num_uses[MAX_RN];
+  #else
+  #error	register use counting unavailable for the parallel engine.
+  #endif
+#endif
 
 /*
 ** The Mercury runtime uses a number of memory areas or *zones*. These
@@ -116,28 +130,48 @@
 #endif	/* HAVE_MPROTECT */
 };
 
-#define MAX_ZONES	16
-
-extern MemoryZone	*zone_table;
-
 	/* A linked list of all the unused zones */
 extern MemoryZone	*free_memory_zones;
 	/* A linked list of all the used zones */
 extern MemoryZone	*used_memory_zones;
 
+#ifndef	MR_PARALLEL
+
 extern MemoryZone	*detstack_zone;
 extern MemoryZone	*nondetstack_zone;
+#ifdef MR_USING_TRAIL
+extern MemoryZone	*trail_zone;
+#endif
 #ifndef CONSERVATIVE_GC
 extern MemoryZone	*heap_zone;
 extern MemoryZone	*solutions_heap_zone;
 extern Word		*solutions_heap_pointer;
-#endif
+#endif /* CONSERVATIVE_GC */
 
 #ifndef	SPEED
 extern	MemoryZone	*dumpstack_zone;
 extern	int		dumpindex;
 #endif
 
+#else
+
+#define detstack_zone		(mr_engine_base->e_detstack_zone)
+#define nondetstack_zone	(mr_engine_base->e_nondetstack_zone)
+#ifdef	MR_USING_TRAIL
+#define trail_zone		(mr_engine_base->e_trail_zone)
+#endif
+#ifndef	CONSERVATIVE_GC
+#define heap_zone		(mr_engine_base->e_heap_zone)
+#define solutions_heap_zone	(mr_engine_base->e_solutions_heap_zone)
+#endif
+
+#ifndef	SPEED
+#define	dumpstack_zone		(mr_engine_base->e_dumpstack_zone)
+#define	dumpindex		(mr_engine_base->e_dumpindex)
+#endif
+
+#endif
+
 /*
 ** create_zone(Name, Id, Size, Offset, RedZoneSize, FaultHandler)
 ** allocates a new memory zone with name Name, and number Id, size
@@ -199,6 +233,16 @@
 extern	void	init_heap(void);
 extern	void	debug_memory(void);
 
+extern	MemoryZone	*create_detstack(void);
+extern	MemoryZone	*create_nondetstack(void);
+#ifdef MR_USING_TRAIL
+extern	MemoryZone	*create_trail(void);
+#endif
+#ifndef CONSERVATIVE_GC
+extern	MemoryZone	*create_heap(void);
+extern	MemoryZone	*create_solutions_heap(void);
+#endif
+
 /*
 ** next_offset() returns sucessive offsets across the primary cache. Useful
 ** when calling {create,construct}_zone().
@@ -212,9 +256,6 @@
 **
 ** allocate_array(type, num) allocates space for an array of objects of the
 ** specified type.
-**
-** If shared memory is being used, these allocation routines will allocate
-** in shared memory.
 */
 
 extern	void	*allocate_bytes(size_t numbytes);
Index: mercury_types.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/mercury_types.h,v
retrieving revision 1.5
diff -u -r1.5 mercury_types.h
--- mercury_types.h	1997/07/27 15:08:31	1.5
+++ mercury_types.h	1997/09/16 00:28:03
@@ -43,9 +43,6 @@
 /* continuation function type, for --high-level-C option */
 typedef void (*Cont) (void);
 
-/* spinlocks -- see spinlock.h */
-typedef Word	SpinLock;
-
 /*
 ** semidet predicates indicate success or failure by leaving nonzero or zero
 ** respectively in register r1
Index: misc.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/misc.h,v
retrieving revision 1.4
diff -u -r1.4 misc.h
--- misc.h	1997/07/27 15:08:33	1.4
+++ misc.h	1997/09/12 02:38:25
@@ -44,9 +44,9 @@
 extern	void	printstring(const char *s);
 extern	void	printheap(const Word *h);
 extern	void	printdetstack(const Word *s);
-extern	void	printnondstack(const Word *s);
+extern	void	printnondetstack(const Word *s);
 extern	void	dumpframe(/* const */ Word *);
-extern	void	dumpnondstack(void);
+extern	void	dumpnondetstack(void);
 extern	void	printlist(Word p);
 extern	void	printframe(const char *);
 extern	void	printregs(const char *msg);
Index: overflow.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/overflow.h,v
retrieving revision 1.7
diff -u -r1.7 overflow.h
--- overflow.h	1997/07/27 15:08:34	1.7
+++ overflow.h	1997/09/12 02:38:32
@@ -16,8 +16,8 @@
 #define	heap_overflow_check()		((void)0)
 #define	detstack_overflow_check()	((void)0)
 #define	detstack_underflow_check()	((void)0)
-#define	nondstack_overflow_check()	((void)0)
-#define	nondstack_underflow_check()	((void)0)
+#define	nondetstack_overflow_check()	((void)0)
+#define	nondetstack_underflow_check()	((void)0)
 
 #else /* not SPEED */
 
@@ -54,7 +54,7 @@
 				(void)0				\
 			)
 
-#define	nondstack_overflow_check()				\
+#define	nondetstack_overflow_check()				\
 			(					\
 				IF (maxfr >= nondetstack_zone->top,(	\
 					fatal_error("nondetstack overflow") \
@@ -65,7 +65,7 @@
 				(void)0				\
 			)
 
-#define	nondstack_underflow_check()				\
+#define	nondetstack_underflow_check()				\
 			(					\
 				IF (maxfr < nondetstack_zone->min,(	\
 					fatal_error("nondetstack underflow") \
Index: regorder.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/regorder.h,v
retrieving revision 1.18
diff -u -r1.18 regorder.h
--- regorder.h	1997/08/23 22:34:18	1.18
+++ regorder.h	1997/09/18 01:38:03
@@ -22,6 +22,8 @@
 #ifndef REGORDER_H
 #define REGORDER_H
 
+#if	!defined(MR_PARALLEL) || (NUM_REAL_REGS < 1)
+
 #define r1		count_usage(R_RN(1), mr2)
 #define r2		count_usage(R_RN(2), mr3)
 #define r3		count_usage(R_RN(3), mr4)
@@ -61,9 +63,8 @@
 #define curfr		LVALUE_CAST(Word *, count_usage(CF_RN, mr8))
 #define maxfr		LVALUE_CAST(Word *, count_usage(MF_RN, mr9))
 
-#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 MR_trail_ptr		count_usage(MR_TRAIL_PTR_RN, mr37)
+#define MR_ticket_counter	count_usage(MR_TICKET_COUNTER_RN, mr38)
 
 #define VIRTUAL_REG_MAP_BODY	{ \
 	2, \
@@ -99,5 +100,90 @@
 	35, \
 	36, \
 }
+
+#ifdef	MR_PARALLEL
+#define mr_engine_base	(get_engine_base())
+#endif
+
+#else
+
+#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), mr18)
+#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 succip		LVALUE_CAST(Code *, count_usage(SI_RN, mr2))
+#define hp		LVALUE_CAST(Word *, count_usage(HP_RN, mr6))
+#define sp		LVALUE_CAST(Word *, count_usage(SP_RN, mr1))
+#define curfr		LVALUE_CAST(Word *, count_usage(CF_RN, mr9))
+#define maxfr		LVALUE_CAST(Word *, count_usage(MF_RN, mr10))
+
+#define MR_trail_ptr		count_usage(MR_TRAIL_PTR_RN, mr38)
+#define MR_ticket_counter	count_usage(MR_TICKET_COUNTER_RN, mr39)
+
+#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, \
+	29, \
+	29, \
+	30, \
+	31, \
+	32, \
+	33, \
+	34, \
+	35, \
+	36, \
+	37, \
+}
+
+#endif	/* MR_PARALLEL */
 
 #endif /* not REGORDER_H */
Index: regs.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/regs.h,v
retrieving revision 1.31
diff -u -r1.31 regs.h
--- regs.h	1997/08/23 22:34:17	1.31
+++ regs.h	1997/09/18 00:54:57
@@ -102,14 +102,40 @@
 ** to their corresponding slots in the fake_reg array 
 */
 
+#ifndef	MR_PARALLEL
 #define save_registers() 	save_regs_to_mem(fake_reg)
+#else
+#error need a definition of save_registers
+#endif
+
+/* 
+** the save_arg_registers() macro copies the physical machine registers
+** that are being used for storing the rN and fN registers to their
+** corresponding slots in the fake_reg array 
+** XXX
+*/
+
+#define save_arg_registers() 	save_regs_to_mem(fake_reg)
 
 /* 
 ** the restore_registers() macro sets the physical machine registers
 ** to the values in their corresponding slots in the fake_reg array 
 */
 
+#ifndef	MR_PARALLEL
 #define restore_registers() 	restore_regs_from_mem(fake_reg)
+#else
+#error need a definition of restore_registers
+#endif
+
+/* 
+** the restore_arg_registers() macro sets the physical machine registers
+** that are being used for storing the rN and fN registers to the values
+** in their corresponding slots in the fake_reg array 
+** XXX
+*/
+
+#define restore_arg_registers() 	restore_regs_from_mem(fake_reg)
 
 /* 
 ** the save_transient_registers() and restore_transient_registers()
Index: spinlock.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/spinlock.c,v
retrieving revision 1.5
diff -u -r1.5 spinlock.c
--- spinlock.c	1997/07/27 15:08:41	1.5
+++ spinlock.c	1997/09/16 23:00:24
@@ -11,6 +11,46 @@
 #include "imp.h"
 #include "spinlock.h"
 
+/*----------------------------------------------------------------------------*/
+
+#ifdef MR_PARALLEL
+
+MR_Mutex *allocate_mutex(void)
+{
+	MR_Mutex *m;
+
+	m = allocate_object(MR_Mutex);
+#ifdef	MR_HAVE_MUTEX_CONST
+	*m = PTHREAD_MUTEX_INITIALIZER;
+#else
+	/*
+	** The man page for pthread_mutex_init says that it
+	** always returns 0, so we don't need to check for
+	** failures.
+	*/
+	pthread_mutex_init(m, MR_MUTEXATTR_DEFAULTS);
+#endif
+	return m;
+}
+
+void deallocate_mutex(MR_Mutex *m)
+{
+	int err;
+
+	err = pthread_mutex_destroy(m);
+	if (err != 0)
+		fatal_error("attempt to deallocate a locked mutex");
+	
+	deallocate_memory(m);
+}
+
+#endif
+
+#if 0
+/*
+** These stubs are starting points for hanging arch-dependent
+** spinlocks on.
+*/
 void 
 do_spinlock(Word *l)
 {
@@ -22,3 +62,36 @@
 {
 	fatal_error("do_spinunlock unimplemented");
 }
+#endif
+
+/*----------------------------------------------------------------------------*/
+
+#ifdef	MR_PARALLEL
+
+MR_Sem *allocate_semaphore(void)
+{
+	MR_Sem *s;
+	int err;
+
+	s = allocate_object(MR_Sem);
+	err = sem_init(s, 0, 0);
+	if (err != 0)
+		fatal_error("failed to initialize semaphore");
+	return s;
+}
+
+void deallocate_semaphore(MR_Sem *s)
+{
+	int err;
+
+	err = sem_destroy(s);
+	if (err != 0)
+		fatal_error("attempt to deallocate semaphore with blocked threads");
+
+	deallocate_memory(s);
+}
+
+#endif
+
+/*----------------------------------------------------------------------------*/
+
Index: spinlock.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/spinlock.h,v
retrieving revision 1.6
diff -u -r1.6 spinlock.h
--- spinlock.h	1997/07/27 15:08:42	1.6
+++ spinlock.h	1997/09/16 22:39:08
@@ -4,38 +4,53 @@
 ** Public License - see the file COPYING.LIB in the Mercury distribution.
 */
 
-/* spinlock.h - defines spin locks (locks obtained by busy-waiting) */
+/*
+** spinlock.h - defines locks (mutexes) which may be implemented either
+** by using pthread mutexes, or for a (possibly) more efficient lock,
+** spinlocks, and condition variables.
+*/
 
 #ifndef SPINLOCK_H
 #define SPINLOCK_H
 
 /*
-** This part of the header file documents the abstract interface for a spinlock.
+** This part of the header file documents the abstract interface for spinlocks
+** and condition variables.
 */
 
 #if 0 /* everything here is really implemented as macros */
 
-/*
-** You can assume that a SpinLock will fit into a Word,
-** i.e. that sizeof(SpinLock) <= sizeof(Word).
-** But you should not assume anything else.
-*/
-typedef ... SpinLock;
+typedef ... MR_Mutex;
+
+typedef ... MR_Sem;
 
 /*
-** allocate_lock() returns a pointer to a new initialized lock,
-** allocated in shared memory.
+** allocate_lock() returns a pointer to a new initialized lock.
 ** deallocate_lock() deinitializes and deallocates a lock.
 */
-extern	SpinLock *allocate_lock(void);
-extern	void deallocate_lock(SpinLock *);
+extern	MR_Mutex *allocate_lock(void);
+extern	void deallocate_lock(MR_Mutex *);
 
 /*
 ** get_lock() and release_lock() are used to
 ** acquire and relinquish a lock.
 */
-void get_lock(SpinLock *);
-void release_lock(SpinLock *);
+void get_lock(MR_Mutex *);
+void release_lock(MR_Mutex *);
+
+/*
+** allocate_sem() returns a pointer to a new initialized semaphore
+** deallocate_sem() deinitializes and deallocates a semaphore
+*/
+extern	MR_Sem *allocate_sem(void);
+extern	void deallocate_sem(MR_Sem *s);
+
+/*
+** mr_sem_signal increments the given semaphore. mr_sem_wait waits on a
+** given semaphore.
+*/
+void mr_sem_signal(MR_Sem *s);
+void mr_sem_wait(MR_Sem *s);
 
 #endif /* 0 */
 
@@ -47,34 +62,35 @@
 ** but code elsewhere should avoid depending on these details.
 */
 
-#include "mercury_types.h"	/* for `SpinLock' and `Word' */
+#include "mercury_types.h"	/* for `Word' */
 #include <stddef.h>		/* for `NULL' */
-#include "conf.h"		/* for `PARALLEL' */
-#include "context.h"		/* for `numprocs' */
+#include <pthread.h>		/* for pthread_mutex_t */
+#include <semaphore.h>		/* for sem_t */
+#include "conf.h"		/* for `MR_PARALLEL' */
 
-void do_spinlock(SpinLock *s);
+typedef	pthread_mutex_t	MR_Mutex;
 
-void do_spinunlock(SpinLock *s);
+#define	do_spinlock(ptr)	pthread_mutex_lock((MR_Mutex *)(ptr))
+#define do_spinunlock(ptr)	pthread_mutex_unlock((MR_Mutex *)(ptr))
 
-#ifdef	PARALLEL
+#ifdef	MR_PARALLEL
 
 #define get_lock(addr)		do {			\
-		if (numprocs != 1) {			\
+		if (numthreads != 1) {			\
 			do_spinlock(addr);	\
 		}					\
 	} while(0)
 
 #define	release_lock(addr)	do {			\
-		if (numprocs != 1) {			\
+		if (numthreads != 1) {			\
 			do_spinunlock(addr);	\
 		}					\
 	} while(0)
 
-#define allocate_lock() 	allocate_object(SpinLock)
-
-#define deallocate_lock(lock)	deallocate(lock)
+MR_Mutex *allocate_lock(void);
+void deallocate_lock(MR_Mutex *m);
 
-#else /* not PARALLEL */
+#else /* not MR_PARALLEL */
 
 #define	get_lock(addr)		do { } while (0)
 
@@ -84,7 +100,23 @@
 
 #define deallocate_lock(lock)	do { } while(0)
 
+#endif /* not MR_PARALLEL */
+
+typedef	sem_t	MR_Sem;
+
+#define	mr_sem_signal(sptr)	sem_post((sem_t *)(sptr))
 
-#endif /* not PARALLEL */
+#define	mr_sem_wait(sptr)	sem_wait((sem_t *)(sptr))
+
+extern MR_Sem	*allocate_semaphore(void);
+extern void	deallocate_semaphore(MR_Sem *sptr);
+
+#if 0
+/*
+** Once we want to start using spinlocks, we'll need these prototypes
+*/
+void do_spinlock(MR_Mutex *s);
+void do_spinunlock(MR_Mutex *s);
+#endif
 
 #endif /* not SPINLOCK_H */
Index: stacks.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/stacks.h,v
retrieving revision 1.9
diff -u -r1.9 stacks.h
--- stacks.h	1997/07/27 15:08:43	1.9
+++ stacks.h	1997/09/12 02:38:38
@@ -124,7 +124,7 @@
 				cursuccfr = succfr;		\
 				mkframe_save_prednm(prednm);	\
 				debugmkframe();			\
-				nondstack_overflow_check();	\
+				nondetstack_overflow_check();	\
 			} while (0)
 
 
@@ -161,7 +161,7 @@
 				debugfail();			\
 				maxfr = curprevfr;		\
 				curfr = maxfr;			\
-				nondstack_underflow_check();	\
+				nondetstack_underflow_check();	\
 				GOTO(curredoip);		\
 			} while (0)
 
Index: wrapper.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/wrapper.h,v
retrieving revision 1.20
diff -u -r1.20 wrapper.h
--- wrapper.h	1997/09/05 23:20:05	1.20
+++ wrapper.h	1997/09/12 02:37:40
@@ -62,14 +62,14 @@
 /* sizes of the data areas, *including* the red zone size */
 extern	size_t		heap_size;
 extern	size_t		detstack_size;
-extern	size_t		nondstack_size;
+extern	size_t		nondetstack_size;
 extern	size_t		solutions_heap_size;
 extern	size_t		trail_size;
 
 /* sizes of the red zones */
 extern	size_t		heap_zone_size;
 extern	size_t		detstack_zone_size;
-extern	size_t		nondstack_zone_size;
+extern	size_t		nondetstack_zone_size;
 extern	size_t		solutions_heap_zone_size;
 extern	size_t		trail_zone_size;
 
Index: wrapper.mod
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/wrapper.mod,v
retrieving revision 1.80
diff -u -r1.80 wrapper.mod
--- wrapper.mod	1997/09/06 12:56:45	1.80
+++ wrapper.mod	1997/09/16 23:29:59
@@ -42,7 +42,7 @@
 /* (but we later multiply by 1024 to convert to bytes) */
 size_t		heap_size =      	4096;
 size_t		detstack_size =  	2048;
-size_t		nondstack_size =  	128;
+size_t		nondetstack_size =  	128;
 size_t		solutions_heap_size =	1024;
 size_t		trail_size =		128;
 
@@ -50,7 +50,7 @@
 /* (but we later multiply by 1024 to convert to bytes) */
 size_t		heap_zone_size =	16;
 size_t		detstack_zone_size =	16;
-size_t		nondstack_zone_size =	16;
+size_t		nondetstack_zone_size =	16;
 size_t		solutions_heap_zone_size = 16;
 size_t		trail_zone_size =	16;
 
@@ -187,7 +187,9 @@
 
 	/* double-check that the garbage collector knows about
 	   global variables in shared libraries */
+/* XXX moved to engine.mod
 	GC_is_visible(fake_reg);
+*/
 
 	/* The following code is necessary to tell the conservative */
 	/* garbage collector that we are using tagged pointers */
@@ -436,7 +438,7 @@
 
 		case 'd':	
 			if (streq(optarg, "b"))
-				nondstackdebug = TRUE;
+				nondetstackdebug = TRUE;
 			else if (streq(optarg, "c"))
 				calldebug    = TRUE;
 			else if (streq(optarg, "d"))
@@ -465,7 +467,7 @@
 				tracedebug   = TRUE;
 			else if (streq(optarg, "a")) {
 				calldebug      = TRUE;
-				nondstackdebug = TRUE;
+				nondetstackdebug = TRUE;
 				detstackdebug  = TRUE;
 				heapdebug      = TRUE;
 				gotodebug      = TRUE;
@@ -507,12 +509,12 @@
 			exit(0);
 		}
 
-#ifdef	PARALLEL
+#ifdef	MR_PARALLEL
 		case 'P':
-				if (sscanf(optarg, "%u", &numprocs) != 1)
+				if (sscanf(optarg, "%u", &numthreads) != 1)
 					usage();
 				
-				if (numprocs < 1)
+				if (numthreads < 1)
 					usage();
 
 				break;
@@ -541,7 +543,7 @@
 			else if (optarg[0] == 'd')
 				detstack_size = size;
 			else if (optarg[0] == 'n')
-				nondstack_size = size;
+				nondetstack_size = size;
 			else if (optarg[0] == 'l')
 				entry_table_size = size *
 					1024 / (2 * sizeof(List *));
@@ -558,7 +560,7 @@
 			use_own_timer = TRUE;
 
 			calldebug      = FALSE;
-			nondstackdebug = FALSE;
+			nondetstackdebug = FALSE;
 			detstackdebug  = FALSE;
 			heapdebug      = FALSE;
 			gotodebug      = FALSE;
@@ -598,7 +600,7 @@
 			else if (optarg[0] == 'd')
 				detstack_zone_size = size;
 			else if (optarg[0] == 'n')
-				nondstack_zone_size = size;
+				nondetstack_zone_size = size;
 #ifdef MR_USE_TRAIL
 			else if (optarg[0] == 't')
 				trail_zone_size = size;
@@ -757,7 +759,7 @@
 #endif
 		printf("max detstack used:  %6ld words\n",
 			(long)(detstack_zone->max - detstack_zone->min));
-		printf("max nondstack used: %6ld words\n",
+		printf("max nondetstack used: %6ld words\n",
 			(long) (nondetstack_zone->max - nondetstack_zone->min));
 	}
 #endif
@@ -853,7 +855,7 @@
 		save_transient_registers();
 		printregs("global succeeded");
 		if (detaildebug)
-			dumpnondstack();
+			dumpnondetstack();
 	}
 #endif
 
@@ -869,7 +871,7 @@
 		printregs("global failed");
 
 		if (detaildebug)
-			dumpnondstack();
+			dumpnondetstack();
 	}
 #endif
 
cvs diff: Diffing machdeps



More information about the developers mailing list