[m-rev.] for post-commit review: par_builtin tweaks

Zoltan Somogyi zs at csse.unimelb.edu.au
Wed Oct 1 16:23:30 AEST 2008


For review by Peter Wang.

Zoltan.

library/par_builtin.m:
	Don't initialize the value field unnecessarily.

	Give MR_ prefixes to structure field names.

	Fix some comments.

cvs diff: Diffing .
Index: par_builtin.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/par_builtin.m,v
retrieving revision 1.13
diff -u -b -r1.13 par_builtin.m
--- par_builtin.m	12 Sep 2007 06:21:13 -0000	1.13
+++ par_builtin.m	1 Oct 2008 06:09:15 -0000
@@ -72,13 +72,14 @@
 
 #ifdef MR_THREAD_SAFE
     struct MR_Future {
-        MercuryLock lock;
             /* lock preventing concurrent accesses */
-        int signalled;
+        MercuryLock     MR_fut_lock;
             /* whether this future has been signalled yet */
-        MR_Context *suspended;
+        int             MR_fut_signalled;
+
             /* linked list of all the contexts blocked on this future */
-        MR_Word value;
+        MR_Context      *MR_fut_suspended;
+        MR_Word         MR_fut_value;
     };
 #else /* !MR_THREAD_SAFE */
     struct MR_Future {
@@ -106,20 +107,24 @@
     MR_incr_hp(fut_addr, MR_round_up(sizeof(MR_Future), sizeof(MR_Word)));
     Future = (MR_Future *) fut_addr;
 
-    pthread_mutex_init(&(Future->lock), MR_MUTEX_ATTR);
+    pthread_mutex_init(&(Future->MR_fut_lock), MR_MUTEX_ATTR);
 
     /*
     ** The mutex needs to be destroyed when the future is garbage collected.
     ** For efficiency we might want to ignore this altogether, e.g. on Linux
     ** pthread_mutex_destroy() only checks that the mutex is unlocked.
+    **
+    ** We initialize the value field only to prevent its previous value,
+    ** which may point to an allocated block, keeping that block alive.
+    ** Semantically, the value field is undefined at this point in time.
     */
   #ifdef MR_CONSERVATIVE_GC
     GC_REGISTER_FINALIZER(Future, MR_finalize_future, NULL, NULL, NULL);
+    Future->MR_fut_value = 0;
   #endif
 
-    Future->signalled = MR_FALSE;
-    Future->suspended = NULL;
-    Future->value = 0;
+    Future->MR_fut_signalled = MR_FALSE;
+    Future->MR_fut_suspended = NULL;
 
 #else
 
@@ -143,7 +148,7 @@
         MR_Future *fut = (MR_Future *) obj;
 
       #ifdef MR_THREAD_SAFE
-        pthread_mutex_destroy(&(fut->lock));
+        pthread_mutex_destroy(&(fut->MR_fut_lock));
       #endif
     }
 #endif
@@ -155,17 +160,27 @@
 "
 #if (!defined MR_HIGHLEVEL_CODE) && (defined MR_THREAD_SAFE)
 
-    MR_LOCK(&(Future->lock), ""future.wait"");
+    /*
+    ** It would be nice if we could rely on an invariant such as
+    ** `if MR_fut_signalled is true, then reading MR_fut_value is ok'
+    ** even *without* wrapping up those two field accesses in the mutex,
+    ** taking the mutex only when MR_fut_signalled is false. (We would
+    ** then have to repeat the test of MR_fut_signalled, of course.)
+    ** Unfortunately, memory systems today cannot be relied on to provide
+    ** the required level of consistency.
+    */
+
+    MR_LOCK(&(Future->MR_fut_lock), ""future.wait"");
 
-    if (Future->signalled) {
-        Value = Future->value;
-        MR_UNLOCK(&(Future->lock), ""future.wait"");
+    if (Future->MR_fut_signalled) {
+        Value = Future->MR_fut_value;
+        MR_UNLOCK(&(Future->MR_fut_lock), ""future.wait"");
     } else {
         MR_Context *ctxt;
 
         /*
-        ** The address of the future can be lost when we resume so save it on
-        ** top of the stack.
+        ** Put the address of the future at a fixed place known to
+        ** mercury__par_builtin__wait_resume, to wit, the top of the stack.
         */
         MR_incr_sp(1);
         MR_sv(1) = (MR_Word) Future;
@@ -178,10 +193,10 @@
         MR_save_context(ctxt);
 
         ctxt->MR_ctxt_resume = MR_ENTRY(mercury__par_builtin__wait_resume);
-        ctxt->MR_ctxt_next = Future->suspended;
-        Future->suspended = ctxt;
+        ctxt->MR_ctxt_next = Future->MR_fut_suspended;
+        Future->MR_fut_suspended = ctxt;
 
-        MR_UNLOCK(&(Future->lock), ""future.wait"");
+        MR_UNLOCK(&(Future->MR_fut_lock), ""future.wait"");
 
         MR_ENGINE(MR_eng_this_context) = NULL;
         MR_runnext();
@@ -225,10 +240,10 @@
         Future = (MR_Future *) MR_sv(1);
         MR_decr_sp(1);
 
-        assert(Future->signalled);
+        assert(Future->MR_fut_signalled);
 
         /* Return to the caller of par_builtin.wait. */
-        MR_r1 = Future->value;
+        MR_r1 = Future->MR_fut_value;
         MR_proceed();
     }
     MR_END_MODULE
@@ -270,8 +285,8 @@
 "
 #if (!defined MR_HIGHLEVEL_CODE) && (defined MR_THREAD_SAFE)
 
-    assert(Future->signalled);
-    Value = Future->value;
+    assert(Future->MR_fut_signalled);
+    Value = Future->MR_fut_value;
 
 #else
 
@@ -290,29 +305,29 @@
     MR_Context *ctxt;
     MR_Context *next;
 
-    MR_LOCK(&(Future->lock), ""future.signal"");
+    MR_LOCK(&(Future->MR_fut_lock), ""future.signal"");
 
     /*
     ** If the same future is passed twice to a procedure then it
     ** could be signalled twice, but the value must be the same.
     */
-    if (Future->signalled) {
-        assert(Future->value == Value);
+    if (Future->MR_fut_signalled) {
+        assert(Future->MR_fut_value == Value);
     } else {
-        Future->signalled = MR_TRUE;
-        Future->value = Value;
+        Future->MR_fut_signalled = MR_TRUE;
+        Future->MR_fut_value = Value;
     }
 
     /* Schedule all the contexts which are blocking on this future. */
-    ctxt = Future->suspended;
+    ctxt = Future->MR_fut_suspended;
     while (ctxt != NULL) {
         next = ctxt->MR_ctxt_next;
         MR_schedule_context(ctxt);  /* clobbers MR_ctxt_next */
         ctxt = next;
     }
-    Future->suspended = NULL;
+    Future->MR_fut_suspended = NULL;
 
-    MR_UNLOCK(&(Future->lock), ""future.signal"");
+    MR_UNLOCK(&(Future->MR_fut_lock), ""future.signal"");
 
 #else
 
--------------------------------------------------------------------------
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