[m-rev.] for review: shift spawn/3 etc, into the standard library

Julien Fischer juliensf at csse.unimelb.edu.au
Mon Jan 15 23:00:38 AEDT 2007


For review by Peter Wang.

The name of the new library module hasn't been finalised yet but
I would like comments on the rest of it.

Estimated hours taken: 2
Branches: main

Shift extras/concurrency/spawn.m into a new standard library module
named `thread'.

library/thread.m:
 	New module.  This contains modified versions of the spawn/3
 	and yield/2 predicates that previously lived in
 	extras/concurrency/spawn.m.  The main modifications are:

 	- we now allow this module to compile in non .par hl* grades.
 	  (Attempting to acutally create a new thread in this grades will
 	  cause a runtime abort.)

 	- s/ME_/ML_/

extras/concurrency/spawn.m:
 	Redefine the old versions of spawn/3 and yield/2 in terms
 	of the versions in the standard library.

 	Mark them as obsolete and add a pointer to the new versions.

NEWS:
 	Annouce the change.

Julien.

Index: NEWS
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/NEWS,v
retrieving revision 1.438
diff -u -r1.438 NEWS
--- NEWS	12 Jan 2007 05:00:32 -0000	1.438
+++ NEWS	15 Jan 2007 11:53:11 -0000
@@ -17,6 +17,9 @@

  Changes to the Mercury standard library:

+* We have moved the concurrency primitives out of the extras distribution and
+  into a new standard library module called `thread'.
+
  * The following predicates have been added to the list module:
  	list.map_corresponding/4
  	list.map2_foldl3/10
Index: extras/concurrency/spawn.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/extras/concurrency/spawn.m,v
retrieving revision 1.18
diff -u -r1.18 spawn.m
--- extras/concurrency/spawn.m	12 Jan 2007 05:00:32 -0000	1.18
+++ extras/concurrency/spawn.m	15 Jan 2007 11:27:02 -0000
@@ -30,6 +30,10 @@
      % and those contained in IO - the list of transactions performed by
      % the continuation of spawn.
      %
+    % NOTE: this predicate is obsolete.  New code should use the 
+    % standard library's version: thread.spawn/3.
+    %
+:- pragma obsolete(spawn.spawn/3).
  :- pred spawn(pred(io, io), io, io).
  :- mode spawn(pred(di, uo) is cc_multi, di, uo) is cc_multi.

@@ -39,6 +43,10 @@
      %
      % NOTE: this is not yet implemented in the hlc.par.gc grade.
      % 
+    % NOTE: this predicate is obsolete.  New code should use the 
+    % standard library's version: thread.yield/2.
+    % 
+:- pragma obsolete(spawn.yield/2).
  :- pred yield(io::di, io::uo) is det.

  %-----------------------------------------------------------------------------%
@@ -46,166 +54,19 @@

  :- implementation.

+:- import_module thread.
+
  :- pragma foreign_decl("C", "
  #if defined(MR_HIGHLEVEL_CODE) && !defined(MR_THREAD_SAFE)
    #error The spawn module requires either hlc.par.gc grade or a non-hlc grade.
  #endif
-
-    #include <stdio.h>
  ").

-:- pragma no_inline(spawn/3).
-:- pragma foreign_proc("C",
-    spawn(Goal::(pred(di, uo) is cc_multi), IO0::di, IO::uo),
-    [promise_pure, will_not_call_mercury, thread_safe],
-"
-#ifndef MR_HIGHLEVEL_CODE
-    MR_Context  *ctxt;
-    ctxt = MR_create_context(""spawn"", MR_CONTEXT_SIZE_REGULAR, NULL);
-    ctxt->MR_ctxt_resume = &&spawn_call_back_to_mercury_cc_multi;
-        /* Store the closure on the top of the new context's stack. */
-    *(ctxt->MR_ctxt_sp) = Goal;
-    ctxt->MR_ctxt_next = NULL;
-    ctxt->MR_ctxt_thread_local_mutables =
-        MR_clone_thread_local_mutables(MR_THREAD_LOCAL_MUTABLES);
-    MR_schedule_context(ctxt);
-    if (0) {
-spawn_call_back_to_mercury_cc_multi:
-        MR_save_registers();
-            /* Get the closure from the top of the stack */
-        call_back_to_mercury_cc_multi(*((MR_Word *)MR_sp));
-        MR_destroy_context(MR_ENGINE(MR_eng_this_context));
-        MR_ENGINE(MR_eng_this_context) = NULL;
-        MR_runnext();
-    }
-#else
-    ME_create_thread(Goal);
-#endif
-    IO = IO0;
-").
+spawn.spawn(Goal, !IO) :-
+    thread.spawn(Goal !IO).

-:- pragma foreign_proc("C#",
-    spawn(Goal::(pred(di, uo) is cc_multi), _IO0::di, _IO::uo),
-    [promise_pure, will_not_call_mercury, thread_safe],
-"{
-    System.Threading.Thread t;
-    MercuryThread mt = new MercuryThread(Goal);
- 
-    t = new System.Threading.Thread(
-            new System.Threading.ThreadStart(mt.execute_goal));
-    t.Start();
-}").
-
-:- pragma no_inline(yield/2).
-:- pragma foreign_proc("C",
-    yield(IO0::di, IO::uo),
-    [promise_pure, will_not_call_mercury, thread_safe], "{
-        /* yield() */
-#ifndef MR_HIGHLEVEL_CODE
-    MR_save_context(MR_ENGINE(MR_eng_this_context));
-    MR_ENGINE(MR_eng_this_context)->MR_ctxt_resume =
-        &&yield_skip_to_the_end;
-    MR_schedule_context(MR_ENGINE(MR_eng_this_context));
-    MR_ENGINE(MR_eng_this_context) = NULL;
-    MR_runnext();
-yield_skip_to_the_end:
-#endif
-    IO = IO0;
-
-}").
-
-yield(!IO).
-
-:- pred call_back_to_mercury(pred(io, io), io, io).
-:- mode call_back_to_mercury(pred(di, uo) is cc_multi, di, uo) is cc_multi.
-:- pragma foreign_export("C",
-    call_back_to_mercury(pred(di, uo) is cc_multi, di, uo),
-    "call_back_to_mercury_cc_multi").
-
-call_back_to_mercury(Goal, !IO) :-
-    Goal(!IO).
-
-:- pragma foreign_decl("C", "
-#ifdef MR_HIGHLEVEL_CODE
-  #include  <pthread.h>
-
-  int ME_create_thread(MR_Word goal);
-  void *ME_thread_wrapper(void *arg);
-
-  typedef struct ME_ThreadWrapperArgs ME_ThreadWrapperArgs;
-  struct ME_ThreadWrapperArgs {
-        MR_Word     goal;
-        MR_Word     *thread_local_mutables;
-  };
-#endif
-").
-
-:- pragma foreign_code("C", "
-#ifdef MR_HIGHLEVEL_CODE
-  int ME_create_thread(MR_Word goal)
-  {
-    ME_ThreadWrapperArgs    *args;
-    pthread_t               thread;
-
-    /*
-    ** We can't allocate `args' on the stack because this function may return
-    ** before the child thread has got all the information it needs out of the
-    ** structure.
-    */
-    args = MR_malloc(sizeof(ME_ThreadWrapperArgs));
-    args->goal = goal;
-    args->thread_local_mutables =
-        MR_clone_thread_local_mutables(MR_THREAD_LOCAL_MUTABLES);
-
-    if (pthread_create(&thread, MR_THREAD_ATTR, ME_thread_wrapper, args)) {
-        MR_fatal_error(""Unable to create thread."");
-    }
-
-    /*
-    ** XXX How do we ensure that the parent thread doesn't terminate until
-    ** the child thread has finished it's processing?
-    ** By the use of mutvars, or leave it up to user?
-    */
-    return MR_TRUE;
-  }
-
-  void *ME_thread_wrapper(void *arg)
-  {
-    ME_ThreadWrapperArgs    *args = arg;
-    MR_Word                 goal;
-
-    if (MR_init_thread(MR_use_now) == MR_FALSE) {
-        MR_fatal_error(""Unable to init thread."");
-    }
-
-    assert(MR_THREAD_LOCAL_MUTABLES == NULL);
-    MR_SET_THREAD_LOCAL_MUTABLES(args->thread_local_mutables);
-
-    goal = args->goal;
-    MR_free(args);
-
-    call_back_to_mercury_cc_multi(goal);
-
-    return NULL;
-  }
-#endif
-").
-
-:- pragma foreign_code("C#", "
-public class MercuryThread {
-    object[] Goal;
-
-    public MercuryThread(object[] g)
-    {
-        Goal = g;
-    }
-
-    public void execute_goal()
-    {
-        spawn.mercury_code.call_back_to_mercury_cc_multi(Goal);
-    }
-}
-").
+spawn.yield(!IO) :-
+    thread.yield(!IO).

  %-----------------------------------------------------------------------------%
  %-----------------------------------------------------------------------------%
Index: library/exception.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/exception.m,v
retrieving revision 1.121
diff -u -r1.121 exception.m
--- library/exception.m	3 Jan 2007 05:17:14 -0000	1.121
+++ library/exception.m	15 Jan 2007 07:55:42 -0000
@@ -10,7 +10,7 @@
  % Main author: fjh.
  % Stability: medium.
  % 
-% This file defines the Mercury interface for exception handling.
+% This module defines the Mercury interface for exception handling.
  %
  % Note that throwing an exception across the C interface won't work.
  % That is, if a Mercury procedure that is exported to C using
Index: library/library.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/library.m,v
retrieving revision 1.100
diff -u -r1.100 library.m
--- library/library.m	22 Dec 2006 05:44:22 -0000	1.100
+++ library/library.m	15 Jan 2007 05:20:42 -0000
@@ -121,6 +121,7 @@
  :- import_module term.
  :- import_module term_io.
  :- import_module term_to_xml.
+:- import_module thread.
  :- import_module time.
  :- import_module tree234.
  :- import_module tree_bitset.
@@ -275,6 +276,7 @@
  mercury_std_library_module("term_size_prof_builtin").
  mercury_std_library_module("term_to_xml").
  mercury_std_library_module("time").
+mercury_std_library_module("thread").
  mercury_std_library_module("tree234").
  mercury_std_library_module("tree_bitset").
  mercury_std_library_module("type_desc").
Index: library/thread.m
===================================================================
RCS file: library/thread.m
diff -N library/thread.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ library/thread.m	15 Jan 2007 11:49:35 -0000
@@ -0,0 +1,219 @@
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2000-2001,2003-2004, 2006-2007 The University of Melbourne.
+% This file may only be copied under the terms of the GNU Library General
+% Public License - see the file COPYING.LIB in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+%
+% File: thread.m.
+% Main author: conway.
+% Stability: medium.
+%
+% This module defines the Mercury concurrency interface.
+%
+% The term `concurrency' here refers to threads, not necessarily to parallel
+% execution.  (The latter is also possible if you are using one of the .par
+% grades and the lowlevel C backend, e.g. grade asm_fast.par.gc).
+%
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- module thread.
+:- interface.
+
+:- import_module io.
+
+%-----------------------------------------------------------------------------%
+
+    % spawn(Closure, IO0, IO) is true iff `IO0' denotes a list of I/O
+    % transactions that is an interleaving of those performed by `Closure'
+    % and those contained in `IO' - the list of transactions performed by
+    % the continuation of spawn/3.
+    %
+:- pred spawn(pred(io, io)::in(pred(di, uo) is cc_multi),
+    io::di, io::uo) is cc_multi.
+
+    % yield(IO0, IO) is logically equivalent to (IO = IO0) but
+    % operationally, yields the Mercury engine to some other thread
+    % if one exists.
+    %
+    % NOTE: this is not yet implemented in the hl*.par.gc grades; currently
+    % it is a no-op in those grades.
+    % 
+:- pred yield(io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+%-----------------------------------------------------------------------------%
+
+:- pragma no_inline(spawn/3).
+:- pragma foreign_proc("C",
+    spawn(Goal::(pred(di, uo) is cc_multi), IO0::di, IO::uo),
+    [promise_pure, will_not_call_mercury, thread_safe],
+"
+#if !defined(MR_HIGHLEVEL_CODE)
+    MR_Context  *ctxt;
+    ctxt = MR_create_context(""spawn"", MR_CONTEXT_SIZE_REGULAR, NULL);
+    ctxt->MR_ctxt_resume = &&spawn_call_back_to_mercury_cc_multi;
+ 
+    /*
+    ** Store the closure on the top of the new context's stack.
+    */
+ 
+    *(ctxt->MR_ctxt_sp) = Goal;
+    ctxt->MR_ctxt_next = NULL;
+    ctxt->MR_ctxt_thread_local_mutables =
+        MR_clone_thread_local_mutables(MR_THREAD_LOCAL_MUTABLES);
+    MR_schedule_context(ctxt);
+    if (0) {
+spawn_call_back_to_mercury_cc_multi:
+        MR_save_registers();
+        /*
+        ** Get the closure from the top of the stack
+        */
+        ML_call_back_to_mercury_cc_multi(*((MR_Word *)MR_sp));
+        MR_destroy_context(MR_ENGINE(MR_eng_this_context));
+        MR_ENGINE(MR_eng_this_context) = NULL;
+        MR_runnext();
+    }
+#else /* MR_HIGHLEVEL_CODE */
+
+#if defined(MR_THREAD_SAFE)
+    ML_create_thread(Goal);
+#else
+    MR_fatal_error(""spawn/3 requires a .par grade in high-level C grades."");
+#endif
+
+#endif /* MR_HIGHLEVEL_CODE */
+    IO = IO0;
+").
+
+:- pragma foreign_proc("C#",
+    spawn(Goal::(pred(di, uo) is cc_multi), _IO0::di, _IO::uo),
+    [promise_pure, will_not_call_mercury, thread_safe],
+"
+    System.Threading.Thread t;
+    MercuryThread mt = new MercuryThread(Goal);
+ 
+    t = new System.Threading.Thread(
+            new System.Threading.ThreadStart(mt.execute_goal));
+    t.Start();
+").
+
+:- pragma no_inline(yield/2).
+:- pragma foreign_proc("C",
+    yield(IO0::di, IO::uo),
+    [promise_pure, will_not_call_mercury, thread_safe],
+"
+#ifndef MR_HIGHLEVEL_CODE
+    MR_save_context(MR_ENGINE(MR_eng_this_context));
+    MR_ENGINE(MR_eng_this_context)->MR_ctxt_resume =
+        &&yield_skip_to_the_end;
+    MR_schedule_context(MR_ENGINE(MR_eng_this_context));
+    MR_ENGINE(MR_eng_this_context) = NULL;
+    MR_runnext();
+yield_skip_to_the_end:
+#endif
+    IO = IO0;
+
+").
+
+yield(!IO).
+
+:- pred call_back_to_mercury(pred(io, io), io, io).
+:- mode call_back_to_mercury(pred(di, uo) is cc_multi, di, uo) is cc_multi.
+:- pragma foreign_export("C",
+    call_back_to_mercury(pred(di, uo) is cc_multi, di, uo),
+    "ML_call_back_to_mercury_cc_multi").
+
+call_back_to_mercury(Goal, !IO) :-
+    Goal(!IO).
+
+:- pragma foreign_decl("C", "
+#if defined(MR_HIGHLEVEL_CODE) && defined(MR_THREAD_SAFE)
+  #include  <pthread.h>
+
+  int ML_create_thread(MR_Word goal);
+  void *ML_thread_wrapper(void *arg);
+
+  typedef struct ML_ThreadWrapperArgs ML_ThreadWrapperArgs;
+  struct ML_ThreadWrapperArgs {
+        MR_Word     goal;
+        MR_Word     *thread_local_mutables;
+  };
+#endif /* MR_HIGHLEVEL_CODE && MR_THREAD_SAFE */
+").
+
+:- pragma foreign_code("C", "
+#if defined(MR_HIGHLEVEL_CODE) && defined(MR_THREAD_SAFE)
+  int ML_create_thread(MR_Word goal)
+  {
+    ML_ThreadWrapperArgs    *args;
+    pthread_t               thread;
+
+    /*
+    ** We can't allocate `args' on the stack because this function may return
+    ** before the child thread has got all the information it needs out of the
+    ** structure.
+    */
+    args = MR_malloc(sizeof(ML_ThreadWrapperArgs));
+    args->goal = goal;
+    args->thread_local_mutables =
+        MR_clone_thread_local_mutables(MR_THREAD_LOCAL_MUTABLES);
+
+    if (pthread_create(&thread, MR_THREAD_ATTR, ML_thread_wrapper, args)) {
+        MR_fatal_error(""Unable to create thread."");
+    }
+
+    /*
+    ** XXX How do we ensure that the parent thread doesn't terminate until
+    ** the child thread has finished it's processing?
+    ** By the use of mutvars, or leave it up to user?
+    */
+    return MR_TRUE;
+  }
+
+  void *ML_thread_wrapper(void *arg)
+  {
+    ML_ThreadWrapperArgs    *args = arg;
+    MR_Word                 goal;
+
+    if (MR_init_thread(MR_use_now) == MR_FALSE) {
+        MR_fatal_error(""Unable to init thread."");
+    }
+
+    MR_assert(MR_THREAD_LOCAL_MUTABLES == NULL);
+    MR_SET_THREAD_LOCAL_MUTABLES(args->thread_local_mutables);
+
+    goal = args->goal;
+    MR_free(args);
+
+    ML_call_back_to_mercury_cc_multi(goal);
+
+    return NULL;
+  }
+#endif /* MR_HIGHLEVEL_CODE && MR_THREAD_SAFE */
+").
+
+:- pragma foreign_code("C#", "
+public class MercuryThread {
+    object[] Goal;
+
+    public MercuryThread(object[] g)
+    {
+        Goal = g;
+    }
+
+    public void execute_goal()
+    {
+        thread.mercury_code.call_back_to_mercury_cc_multi(Goal);
+    }
+}").
+
+%-----------------------------------------------------------------------------%
+:- end_module thread.
+%-----------------------------------------------------------------------------%

--------------------------------------------------------------------------
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