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