[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