[m-rev.] for review: bug fixes for threads

Peter Wang wangp at students.csse.unimelb.edu.au
Tue Feb 20 16:09:56 AEDT 2007


Pending bootchecking in more grades.

Branches: main

Some bug fixes to do with threads.

library/io.m:
	ML_maybe_make_err_msg() was not thread-safe but was called from some
	`thread_safe' foreign_procs.  Make ML_maybe_make_err_msg() acquire the
	global lock if the caller does not acquire the global lock itself.

library/thread.m:
runtime/mercury_thread.c:
	Create threads in the detached state so that resources will be
	automatically freed when threads terminate (we don't call
	pthread_join() anywhere).

library/thread.semaphore.m:
	Wake up waiting threads in FIFO order, instead of LIFO order.

runtime/mercury_context.c:
runtime/mercury_context.h:
runtime/mercury_engine.c:
runtime/mercury_engine.h:
	Change the way we enforce that a Mercury context returning from Mercury
	code back into a C function runs on the original Mercury engine that
	called the C function.

	Previously, if a C function called into Mercury code, the Mercury
	context would be "owned" by that Mercury engine until the C function
	finished.  If the Mercury code suspended (e.g. waiting on a semaphore),
	it could not be resumed by another Mercury engine.  This was
	unnecessarily conservative.

	Now any Mercury engine can resume a suspended context.  Just before
	returning into C functions, we check that the context is actually
	running on the Mercury engine in which the C function was started.  If
	not, *then* we reschedule the context so that it will only be picked up
	by the right Mercury engine.

	Add a comment that none of this is implemented for grades not using gcc
	non-local gotos (nor was it implemented before).

runtime/mercury_memory_zones.c:
	Fix an off-by-one bug and a thread-safety bug in MR_next_offset().


====================

Here are some numbers for parallel mmc make after this patch.
It's making the standard library on saturn.

asm_fast.gc:

	time MERCURY_OPTIONS=-P1 mmc -m libmer_std.a --flags LIB_FLAGS
	... 122.08s user 17.27s system 93% cpu 2:29.46 total

	rm Mercury/os/*.o
	time MERCURY_OPTIONS=-P1 mmc -m libmer_std.a --flags LIB_FLAGS
	...  66.04s user  5.91s system 99% cpu 1:11.98 total

asm_fast.par.gc:

	rm -r Mercury
	time MERCURY_OPTIONS=-P1 mmc -m libmer_std.a --flags LIB_FLAGS
	... 145.51s user 20.48s system 101% cpu 2:42.86 total

	rm Mercury/os/*.o
	time MERCURY_OPTIONS=-P1 mmc -m libmer_std.a --flags LIB_FLAGS
	...  66.22s user  5.13s system 100% cpu 1:11.31 total

	rm -r Mercury
	time MERCURY_OPTIONS=-P2 mmc -m libmer_std.a --flags LIB_FLAGS -j2
	... 146.29s user 19.63s system 129% cpu 2:07.99 total

	rm Mercury/os/*.o
	time MERCURY_OPTIONS=-P2 mmc -m libmer_std.a --flags LIB_FLAGS -j2
	...  66.62s user  6.28s system 191% cpu 38.090 total

	rm Mercury/os/*.o
	time MERCURY_OPTIONS=-P4 mmc -m libmer_std.a --flags LIB_FLAGS -j4
	...  66.96s user  7.16s system 197% cpu 37.624 total



Index: library/io.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/io.m,v
retrieving revision 1.372
diff -u -r1.372 io.m
--- library/io.m	13 Feb 2007 01:58:53 -0000	1.372
+++ library/io.m	16 Feb 2007 02:31:40 -0000
@@ -2359,7 +2359,7 @@
     }
 
     ML_maybe_make_err_msg(RetVal != 0, errno, ""read failed: "",
-        MR_PROC_LABEL, RetStr);
+        MR_PROC_LABEL, MR_TRUE, RetStr);
     MR_update_io(IO0, IO);
 ").
 
@@ -2426,7 +2426,7 @@
     [will_not_call_mercury, promise_pure, tabled_for_io,
         does_not_affect_liveness],
 "
-    ML_maybe_make_err_msg(MR_TRUE, Error, Msg0, MR_PROC_LABEL, Msg);
+    ML_maybe_make_err_msg(MR_TRUE, Error, Msg0, MR_PROC_LABEL, MR_FALSE, Msg);
     MR_update_io(IO0, IO);
 ").
 
@@ -2612,7 +2612,7 @@
         Status = 1;
     } else {
         ML_maybe_make_err_msg(MR_TRUE, errno, ""stat() failed: "",
-            MR_PROC_LABEL, Msg);
+            MR_PROC_LABEL, MR_TRUE, Msg);
         Status = 0;
     }
 #else
@@ -3397,7 +3397,7 @@
         Status = 1;
     } else {
         ML_maybe_make_err_msg(MR_TRUE, errno, ""stat() failed: "",
-            MR_PROC_LABEL, Msg);
+            MR_PROC_LABEL, MR_TRUE, Msg);
         Status = 0;
     }
     MR_update_io(IO0, IO);
@@ -8046,7 +8046,7 @@
         */
         Status = 127;
         ML_maybe_make_err_msg(MR_TRUE, errno,
-            ""error invoking system command: "", MR_PROC_LABEL, Msg);
+            ""error invoking system command: "", MR_PROC_LABEL, MR_TRUE, Msg);
     } else {
         Msg = MR_make_string_const("""");
     }
@@ -8478,12 +8478,14 @@
         num_tries < ML_MAX_TEMPNAME_TRIES);
     if (fd == -1) {
         ML_maybe_make_err_msg(MR_TRUE, errno,
-            ""error opening temporary file: "", MR_PROC_LABEL, ErrorMessage);
+            ""error opening temporary file: "", MR_PROC_LABEL, MR_TRUE,
+            ErrorMessage);
         Error = -1;
     }  else {
         err = close(fd);
         ML_maybe_make_err_msg(err, errno,
-            ""error closing temporary file: "", MR_PROC_LABEL, ErrorMessage);
+            ""error closing temporary file: "", MR_PROC_LABEL, MR_TRUE,
+            ErrorMessage);
         Error = err;
     }
     MR_update_io(IO0, IO);
@@ -8604,9 +8606,11 @@
 #include <errno.h>
 
 /*
-** ML_maybe_make_err_msg(was_error, errno, msg, procname, error_msg):
+** ML_maybe_make_err_msg(was_error, errno, msg, procname, req_lock, error_msg):
 ** if `was_error' is true, then append `msg' and `strerror(errno)'
 ** to give `error_msg'; otherwise, set `error_msg' to "".
+** `req_lock' must be true iff the caller is marked `thread_safe' as the
+** underlying strerror() function is not thread-safe.
 **
 ** WARNING: this must only be called when the `hp' register is valid.
 ** That means it must only be called from procedures declared
@@ -8619,13 +8623,17 @@
 ** stringizes the procname argument.
 */
 
-#define ML_maybe_make_err_msg(was_error, error, msg, procname, error_msg)   \\
+#define ML_maybe_make_err_msg(was_error, error, msg, procname, req_lock,    \\
+            error_msg)                                                      \\
     do {                                                                    \\
         char    *errno_msg;                                                 \\
         size_t  total_len;                                                  \\
         MR_Word tmp;                                                        \\
                                                                             \\
         if (was_error) {                                                    \\
+            if (req_lock) {                                                 \\
+                MR_OBTAIN_GLOBAL_LOCK(procname);                            \\
+            }                                                               \\
             errno_msg = strerror(error);                                    \\
             total_len = strlen(msg) + strlen(errno_msg);                    \\
             MR_offset_incr_hp_atomic_msg(tmp, 0,                            \\
@@ -8634,6 +8642,9 @@
             (error_msg) = (char *) tmp;                                     \\
             strcpy((error_msg), msg);                                       \\
             strcat((error_msg), errno_msg);                                 \\
+            if (req_lock) {                                                 \\
+                MR_RELEASE_GLOBAL_LOCK(procname);                           \\
+            }                                                               \\
         } else {                                                            \\
             /*                                                              \\
             ** We can't just return NULL here, because otherwise mdb        \\
@@ -8733,7 +8744,7 @@
 "{
     RetVal = remove(FileName);
     ML_maybe_make_err_msg(RetVal != 0, errno, ""remove failed: "",
-        MR_PROC_LABEL, RetStr);
+        MR_PROC_LABEL, MR_TRUE, RetStr);
     MR_update_io(IO0, IO);
 }").
 
@@ -8798,7 +8809,7 @@
 "{
     RetVal = rename(OldFileName, NewFileName);
     ML_maybe_make_err_msg(RetVal != 0, errno, ""rename failed: "",
-        MR_PROC_LABEL, RetStr);
+        MR_PROC_LABEL, MR_TRUE, RetStr);
     MR_update_io(IO0, IO);
 }").
 
Index: library/thread.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/thread.m,v
retrieving revision 1.5
diff -u -r1.5 thread.m
--- library/thread.m	13 Feb 2007 00:16:57 -0000	1.5
+++ library/thread.m	16 Feb 2007 01:20:11 -0000
@@ -248,6 +248,7 @@
   {
     ML_ThreadWrapperArgs    *args;
     pthread_t               thread;
+    pthread_attr_t          attrs;
 
     /*
     ** We can't allocate `args' on the stack because this function may return
@@ -259,9 +260,12 @@
     args->thread_local_mutables =
         MR_clone_thread_local_mutables(MR_THREAD_LOCAL_MUTABLES);
 
+    pthread_attr_init(&attrs);
+    pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
     if (pthread_create(&thread, MR_THREAD_ATTR, ML_thread_wrapper, args)) {
         MR_fatal_error(""Unable to create thread."");
     }
+    pthread_attr_destroy(&attrs);
 
     /*
     ** XXX How do we ensure that the parent thread doesn't terminate until
Index: library/thread.semaphore.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/thread.semaphore.m,v
retrieving revision 1.4
diff -u -r1.4 thread.semaphore.m
--- library/thread.semaphore.m	6 Feb 2007 10:52:24 -0000	1.4
+++ library/thread.semaphore.m	16 Feb 2007 01:31:04 -0000
@@ -67,7 +67,8 @@
     typedef struct ML_SEMAPHORE_STRUCT {
         int     count;
 #ifndef MR_HIGHLEVEL_CODE
-        MR_Context  *suspended;
+        MR_Context  *suspended_head;
+        MR_Context  *suspended_tail;
 #else
   #ifdef MR_THREAD_SAFE
         MercuryCond cond;
@@ -109,7 +110,8 @@
     sem = (ML_Semaphore *) sem_mem;
     sem->count = 0;
 #ifndef MR_HIGHLEVEL_CODE
-    sem->suspended = NULL;
+    sem->suspended_head = NULL;
+    sem->suspended_tail = NULL;
 #else
   #ifdef MR_THREAD_SAFE
     pthread_cond_init(&(sem->cond), MR_COND_ATTR);
@@ -181,26 +183,35 @@
     MR_LOCK(&(sem->lock), ""semaphore__signal"");
 
 #ifndef MR_HIGHLEVEL_CODE
-    if (sem->count >= 0 && sem->suspended != NULL) {
-        ctxt = sem->suspended;
-        sem->suspended = ctxt->MR_ctxt_next;
+    if (sem->count >= 0 && sem->suspended_head != NULL) {
+        /* Reschedule the context at the start of the queue. */
+        ctxt = sem->suspended_head;
+        sem->suspended_head = ctxt->MR_ctxt_next;
+        if (sem->suspended_tail == ctxt) {
+            sem->suspended_tail = ctxt->MR_ctxt_next;
+            assert(sem->suspended_tail == NULL);
+        }
         MR_UNLOCK(&(sem->lock), ""semaphore__signal"");
         MR_schedule_context(ctxt);
-            /* yield() */
+
+        /* yield() */
         MR_save_context(MR_ENGINE(MR_eng_this_context));
         MR_ENGINE(MR_eng_this_context)->MR_ctxt_resume =
             MR_ENTRY(mercury__thread__semaphore__nop);
         MR_schedule_context(MR_ENGINE(MR_eng_this_context));
+
         MR_ENGINE(MR_eng_this_context) = NULL;
         MR_runnext();
     } else {
         sem->count++;
         MR_UNLOCK(&(sem->lock), ""semaphore__signal"");
-            /* yield() */
+
+        /* yield() */
         MR_save_context(MR_ENGINE(MR_eng_this_context));
         MR_ENGINE(MR_eng_this_context)->MR_ctxt_resume =
             MR_ENTRY(mercury__thread__semaphore__nop);
         MR_schedule_context(MR_ENGINE(MR_eng_this_context));
+
         MR_ENGINE(MR_eng_this_context) = NULL;
         MR_runnext();
     }
@@ -249,11 +260,21 @@
         MR_UNLOCK(&(sem->lock), ""semaphore__wait"");
     } else {
         MR_save_context(MR_ENGINE(MR_eng_this_context));
-        MR_ENGINE(MR_eng_this_context)->MR_ctxt_resume =
-            MR_ENTRY(mercury__thread__semaphore__nop);
-        MR_ENGINE(MR_eng_this_context)->MR_ctxt_next = sem->suspended;
-        sem->suspended = MR_ENGINE(MR_eng_this_context);
+
+        /* Put the current context at the end of the queue. */
+        ctxt = MR_ENGINE(MR_eng_this_context);
+        ctxt->MR_ctxt_resume = MR_ENTRY(mercury__thread__semaphore__nop);
+        ctxt->MR_ctxt_next = NULL;
+        if (sem->suspended_tail) {
+            sem->suspended_tail->MR_ctxt_next = ctxt;
+            sem->suspended_tail = ctxt;
+        } else {
+            sem->suspended_head = ctxt;
+            sem->suspended_tail = ctxt;
+        }
         MR_UNLOCK(&(sem->lock), ""semaphore__wait"");
+
+        /* Make the current engine do something else. */
         MR_ENGINE(MR_eng_this_context) = NULL;
         MR_runnext();
     }
Index: runtime/mercury_context.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_context.c,v
retrieving revision 1.54
diff -u -r1.54 mercury_context.c
--- runtime/mercury_context.c	12 Jan 2007 05:00:30 -0000	1.54
+++ runtime/mercury_context.c	16 Feb 2007 02:26:05 -0000
@@ -115,7 +115,9 @@
     c->MR_ctxt_next = NULL;
     c->MR_ctxt_resume = NULL;
 #ifdef  MR_THREAD_SAFE
-    c->MR_ctxt_owner_thread = (MercuryThread) NULL;
+    c->MR_ctxt_resume_owner_thread = (MercuryThread) NULL;
+    c->MR_ctxt_resume_c_depth = 0;
+    c->MR_ctxt_saved_owners = NULL;
 #endif
 
 #ifndef MR_HIGHLEVEL_CODE
@@ -456,7 +458,7 @@
     ** possibility that a woken thread might not accept this context then
     ** we wake up all the waiting threads.
     */
-    if (ctxt->MR_ctxt_owner_thread == (MercuryThread) NULL) {
+    if (ctxt->MR_ctxt_resume_owner_thread == (MercuryThread) NULL) {
         MR_SIGNAL(&MR_runqueue_cond);
     } else {
         MR_BROADCAST(&MR_runqueue_cond);
@@ -531,12 +533,20 @@
         /* XXX check pending io */
         prev = NULL;
         while (tmp != NULL) {
-            if ((depth > 0 && tmp->MR_ctxt_owner_thread == thd) ||
-                (tmp->MR_ctxt_owner_thread == (MercuryThread) NULL))
+            if (tmp->MR_ctxt_resume_owner_thread == thd && 
+                tmp->MR_ctxt_resume_c_depth == depth)
             {
+                tmp->MR_ctxt_resume_owner_thread = (MercuryThread) NULL;
+                tmp->MR_ctxt_resume_c_depth = 0;
                 MR_num_idle_engines--;
                 goto ReadyContext;
             }
+
+            if (tmp->MR_ctxt_resume_owner_thread == (MercuryThread) NULL) {
+                MR_num_idle_engines--;
+                goto ReadyContext;
+            }
+
             prev = tmp;
             tmp = tmp->MR_ctxt_next;
         }
@@ -550,7 +560,8 @@
         }
 
         /* Nothing to do, go back to sleep. */
-        MR_WAIT(&MR_runqueue_cond, &MR_runqueue_lock);
+        while (MR_WAIT(&MR_runqueue_cond, &MR_runqueue_lock) != 0) {
+        }
     }
 
   ReadyContext:
Index: runtime/mercury_context.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_context.h,v
retrieving revision 1.39
diff -u -r1.39 mercury_context.h
--- runtime/mercury_context.h	12 Jan 2007 05:00:31 -0000	1.39
+++ runtime/mercury_context.h	16 Feb 2007 03:17:19 -0000
@@ -88,9 +88,21 @@
 ** resume           A pointer to the code at which execution should resume
 **                  when this context is next scheduled.
 **
-** owner_thread     The owner_thread field is used to ensure that when we
-**                  enter a Mercury engine from C, we return to the same
-**                  engine. See the coments in mercury_engine.h.
+** resume_owner_thread
+** resume_c_depth
+**                  These fields are used to ensure that when we enter a
+**                  Mercury engine from C, we return to the same engine. If
+**                  resume_owner_thread is NULL then this context can be
+**                  executed by any engine. Otherwise the resume_owner_thread
+**                  and resume_c_depth must match the engine's owner_thread
+**                  and c_depth. See the comments in mercury_engine.h.
+**
+** saved_owners
+**                  A stack used to record the Mercury engines on which this
+**                  context executed some C calls that called back into
+**                  Mercury. We must execute this context in the correct
+**                  engine when returning to those C calls.  See the comments
+**                  in mercury_engine.h.
 **
 ** succip           The succip for this context.
 **
@@ -140,6 +152,16 @@
     MR_CONTEXT_SIZE_SMALL
 } MR_ContextSize;
 
+#ifdef MR_THREAD_SAFE
+typedef struct MR_SavedOwner_Struct     MR_SavedOwner;
+
+struct MR_SavedOwner_Struct {
+    MercuryThread       MR_saved_owner_thread;
+    MR_Unsigned         MR_saved_owner_c_depth;
+    MR_SavedOwner       *MR_saved_owner_next;
+};
+#endif
+
 typedef struct MR_MemoryZones_Struct    MR_MemoryZones;
 
 struct MR_MemoryZones_Struct {
@@ -153,7 +175,9 @@
     MR_Context          *MR_ctxt_next;
     MR_Code             *MR_ctxt_resume;
 #ifdef  MR_THREAD_SAFE
-    MercuryThread       MR_ctxt_owner_thread;
+    MercuryThread       MR_ctxt_resume_owner_thread;
+    MR_Unsigned         MR_ctxt_resume_c_depth;
+    MR_SavedOwner       *MR_ctxt_saved_owners;
 #endif
 
 #ifndef MR_HIGHLEVEL_CODE
Index: runtime/mercury_engine.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_engine.c,v
retrieving revision 1.55
diff -u -r1.55 mercury_engine.c
--- runtime/mercury_engine.c	11 Dec 2006 03:03:13 -0000	1.55
+++ runtime/mercury_engine.c	16 Feb 2007 04:07:40 -0000
@@ -37,6 +37,7 @@
 
   #ifndef MR_USE_GCC_NONLOCAL_GOTOS
     static MR_Code  *engine_done(void);
+    static MR_Code  *engine_done_2(void);
     static MR_Code  *engine_init_registers(void);
   #endif
 
@@ -138,7 +139,6 @@
 #ifdef  MR_THREAD_SAFE
     eng->MR_eng_owner_thread = pthread_self();
     eng->MR_eng_c_depth = 0;
-    eng->MR_eng_saved_owners = NULL;
 #endif
 
     /*
@@ -415,6 +415,7 @@
 
     if (!initialized) {
         MR_make_label("engine_done", MR_LABEL(engine_done), engine_done);
+        MR_make_label("engine_done_2", MR_LABEL(engine_done_2), engine_done_2);
         initialized = MR_TRUE;
     }
 }
@@ -458,21 +459,20 @@
 
     /*
     ** Increment the number of times we've entered this engine from C,
-    ** and mark the current context as being owned by this thread.
+    ** and push the current engine onto the context's stack of saved owners.
     */
 #ifdef  MR_THREAD_SAFE
     MR_ENGINE(MR_eng_c_depth)++;
-    if (MR_ENGINE(MR_eng_this_context)) {
-        MercuryThreadList *new_element;
 
-        new_element = MR_GC_NEW(MercuryThreadList);
-        new_element->thread =
-            MR_ENGINE(MR_eng_this_context)->MR_ctxt_owner_thread;
-        new_element->next = MR_ENGINE(MR_eng_saved_owners);
-        MR_ENGINE(MR_eng_saved_owners) = new_element;
+    if (MR_ENGINE(MR_eng_this_context)) {
+        MR_SavedOwner *owner;
 
-        MR_ENGINE(MR_eng_this_context)->MR_ctxt_owner_thread =
-            MR_ENGINE(MR_eng_owner_thread);
+        owner = MR_GC_NEW(MR_SavedOwner);
+        owner->MR_saved_owner_thread = MR_ENGINE(MR_eng_owner_thread);
+        owner->MR_saved_owner_c_depth = MR_ENGINE(MR_eng_c_depth);
+        owner->MR_saved_owner_next =
+            MR_ENGINE(MR_eng_this_context)->MR_ctxt_saved_owners;
+        MR_ENGINE(MR_eng_this_context)->MR_ctxt_saved_owners = owner;
     }
 #endif
 
@@ -484,31 +484,48 @@
 
 MR_define_label(engine_done);
 
+    assert(MR_ENGINE(MR_eng_this_context));
+
     /*
-    ** Decrement the number of times we've entered this engine from C
-    ** and restore the owning thread in the current context.
+    ** Check that we're reentering C in the correct engine.
+    ** If not, reschedule the context so that it will be picked up by
+    ** the correct engine when it is available.
     */
 #ifdef  MR_THREAD_SAFE
-    if (MR_ENGINE(MR_eng_this_context)) {
-        MercuryThreadList *tmp;
-        MercuryThread val;
+    {
+        MR_Context      *this_ctxt;
+        MR_SavedOwner   *owner;
 
-        assert(MR_ENGINE(MR_eng_this_context)->MR_ctxt_owner_thread
-            == MR_ENGINE(MR_eng_owner_thread));
-        MR_ENGINE(MR_eng_c_depth)--;
-
-        tmp = MR_ENGINE(MR_eng_saved_owners);
-        if (tmp != NULL) {
-            val = tmp->thread;
-            MR_ENGINE(MR_eng_saved_owners) = tmp->next;
-            MR_GC_free(tmp);
-        } else {
-            val = 0;
+        this_ctxt = MR_ENGINE(MR_eng_this_context);
+        owner = this_ctxt->MR_ctxt_saved_owners;
+        this_ctxt->MR_ctxt_saved_owners = owner->MR_saved_owner_next;
+
+        if (owner->MR_saved_owner_thread == MR_ENGINE(MR_eng_owner_thread) &&
+            owner->MR_saved_owner_c_depth == MR_ENGINE(MR_eng_c_depth))
+        {
+            MR_GC_free(owner);
+            MR_GOTO_LABEL(engine_done_2);
         }
-        MR_ENGINE(MR_eng_this_context)->MR_ctxt_owner_thread = val;
+
+        MR_save_context(this_ctxt);
+        this_ctxt->MR_ctxt_resume = MR_LABEL(engine_done_2);
+        this_ctxt->MR_ctxt_resume_owner_thread = owner->MR_saved_owner_thread;
+        this_ctxt->MR_ctxt_resume_c_depth = owner->MR_saved_owner_c_depth;
+        MR_GC_free(owner);
+        MR_schedule_context(this_ctxt);
+
+        MR_ENGINE(MR_eng_this_context) = NULL;
+        MR_runnext();
     }
 #endif
 
+MR_define_label(engine_done_2);
+
+#ifdef MR_THREAD_SAFE
+    /* Decrement the number of times we've entered this engine from C. */
+    MR_ENGINE(MR_eng_c_depth)--;
+#endif
+
     MR_debugmsg1("in label `engine_done', locals at %p\n", locals);
 
 #ifdef MR_LOWLEVEL_DEBUG
@@ -575,6 +592,11 @@
 ** engine_init_registers() rather than directly from call_engine_inner()
 ** because otherwise their value would get mucked up because of the function
 ** call from call_engine_inner().
+**
+** XXX The portable version does not yet prevent Mercury code returning back
+** into C code on the wrong Mercury engine (see the code involving
+** MR_eng_owner_thread and MR_eng_c_depth in the gcc version).  Therefore
+** low-level .par grades without gcc non-local gotos are unsafe.
 */
 
 static MR_Code *
Index: runtime/mercury_engine.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_engine.h,v
retrieving revision 1.45
diff -u -r1.45 mercury_engine.h
--- runtime/mercury_engine.h	27 Dec 2006 04:16:36 -0000	1.45
+++ runtime/mercury_engine.h	16 Feb 2007 01:55:45 -0000
@@ -263,13 +263,6 @@
 
 /*---------------------------------------------------------------------------*/
 
-#ifdef  MR_THREAD_SAFE
-typedef struct MR_mercury_thread_list_struct {
-    MercuryThread                           thread;
-    struct MR_mercury_thread_list_struct    *next;
-} MercuryThreadList;
-#endif
-
 /*
 ** The Mercury engine structure. Normally there is one of these for each
 ** Posix thread. It contains the following fields.
@@ -311,21 +304,19 @@
 **
 ** owner_thread
 ** c_depth
-** saved_owners
-**              These three fields are used to ensure that when a thread
+**              These fields are used to ensure that when a thread
 **              executing C code calls the Mercury engine associated with that
 **              thread, the Mercury code will finish in the same engine and
 **              return appropriately. Each time C calls Mercury in a thread,
-**              the c_depth is incremented, and the owner_thread field of the
-**              current context is set to the id of the thread. While the
-**              owner_thread is set, the context will not be scheduled for
-**              execution by any other thread. When the call to the Mercury
-**              engine finishes, c_depth is decremented and the owner_thread
-**              field of the current context is restored to its previous value.
-**              The list `saved_owners' is used in call_engine_inner to store
-**              the owner of a context across calls into Mercury. At the moment
-**              this is only used for sanity checking - that execution never
-**              returns into C in the wrong thread.
+**              the c_depth is incremented, and the owner_thread and c_depth
+**              values of the current engine are pushed onto the "saved_owners"
+**              stack of the current context. When a context is about to return
+**              from Mercury code back into C code, we pop the top entry off the
+**              context's saved_owners stack and check that the context is
+**              running on the right engine. If not, we reschedule the context
+**              such that it can only be picked up by the correct engine when
+**              that engine is available. When the call into the Mercury code
+**              finishes, c_depth is decremented.
 **
 ** jmp_buf      The jump buffer used by library/exception.m to return to the
 **              runtime system on otherwise unhandled exceptions.
@@ -372,8 +363,7 @@
 #endif
 #ifdef  MR_THREAD_SAFE
     MercuryThread       MR_eng_owner_thread;
-    unsigned            MR_eng_c_depth;
-    MercuryThreadList   *MR_eng_saved_owners;
+    MR_Unsigned         MR_eng_c_depth;
 #endif
     jmp_buf             *MR_eng_jmp_buf;
     MR_Word             *MR_eng_exception;
Index: runtime/mercury_memory_zones.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_memory_zones.c,v
retrieving revision 1.31
diff -u -r1.31 mercury_memory_zones.c
--- runtime/mercury_memory_zones.c	14 Dec 2006 10:29:58 -0000	1.31
+++ runtime/mercury_memory_zones.c	20 Feb 2007 05:03:19 -0000
@@ -489,8 +489,10 @@
 {
     size_t offset;
 
+    MR_OBTAIN_GLOBAL_LOCK("MR_next_offset");
     offset = offset_vector[offset_counter];
-    offset_counter = (offset_counter + 1) % CACHE_SLICES;
+    offset_counter = (offset_counter + 1) % (CACHE_SLICES - 1);
+    MR_RELEASE_GLOBAL_LOCK("MR_next_offset");
     return offset;
 }
 
Index: runtime/mercury_thread.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_thread.c,v
retrieving revision 1.30
diff -u -r1.30 mercury_thread.c
--- runtime/mercury_thread.c	16 Jan 2007 23:45:05 -0000	1.30
+++ runtime/mercury_thread.c	15 Feb 2007 10:37:37 -0000
@@ -49,7 +49,9 @@
 
     thread = MR_GC_NEW(MercuryThread);
     pthread_attr_init(&attrs);
+    pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
     err = pthread_create(thread, &attrs, MR_create_thread_2, (void *) goal);
+    pthread_attr_destroy(&attrs);
 
 #if 0
     fprintf(stderr, "pthread_create returned %d (errno = %d)\n", err, errno);
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list