[m-rev.] for review: Add thread.spawn_native/4 and thread.spawn/4.
Peter Wang
novalazy at gmail.com
Fri Jun 27 14:25:55 AEST 2014
On Fri, 27 Jun 2014 11:54:00 +1000 (EST), Julien Fischer <jfischer at opturion.com> wrote:
>
> Hi Peter,
>
> On Wed, 25 Jun 2014, Peter Wang wrote:
>
> > -%-----------------------------------------------------------------------------%
> > -
> > :- implementation.
> >
> > +:- import_module bool.
> > +:- import_module require.
> > +:- import_module string.
> > +
> > :- pragma foreign_decl("C", "
> > #ifndef MR_HIGHLEVEL_CODE
> > #if (!defined(MR_EXEC_TRACE) && !defined(MR_DEEP_PROFILING)) || !defined(MR_USE_GCC_NONLOCAL_GOTOS)
> > @@ -91,32 +122,54 @@
> > #endif
> > ").
> >
> > + % Nothing yet but it can be used to hold a thread id, joining, holding
> > + % uncaught exception values, etc.
> > +:- type thread
> > + ---> thread.
>
> Using a dummy type as the definition for thread handles means that all
> thread handles will unify and compare as equal. (Which surely shouldn't
> be the case if the originate from different calls to spawn.)
Here is a followup patch.
On second thought, I don't know if thread handles themselves should be
comparable. I think we should provide a function to get the thread_id
which can be compared.
:- func thread_id(thread) = thread_id.
Peter
---
Add thread ids to thread handles.
Thread handles should not be dummy types because all thread handles
would compare equal. Add thread ids to thread handles.
library/thread.m:
As above.
Reduce accessibility levels in C# and Java helper classes.
diff --git a/library/thread.m b/library/thread.m
index 428ee2a..4e3739b 100644
--- a/library/thread.m
+++ b/library/thread.m
@@ -122,10 +122,13 @@
#endif
").
- % Nothing yet but it can be used to hold a thread id, joining, holding
- % uncaught exception values, etc.
+ % The thread id is not formally exposed yet but allows different thread
+ % handles to compare unequal.
+ %
:- type thread
- ---> thread.
+ ---> thread(thread_id).
+
+:- type thread_id == string.
%-----------------------------------------------------------------------------%
@@ -200,41 +203,54 @@ spawn(Goal, Res, !IO) :-
:- mode spawn_context(pred(in, di, uo) is cc_multi, out, di, uo) is cc_multi.
spawn_context(Goal, Res, !IO) :-
- spawn_context_2(Goal, Success, !IO),
+ spawn_context_2(Goal, Success, ThreadId, !IO),
(
Success = yes,
- Res = ok(thread)
+ Res = ok(thread(ThreadId))
;
Success = no,
Res = error("Unable to spawn threads in this grade.")
).
-:- pred spawn_context_2(pred(thread, io, io), bool, io, io).
-:- mode spawn_context_2(pred(in, di, uo) is cc_multi, out, di, uo) is cc_multi.
+:- pred spawn_context_2(pred(thread, io, io), bool, string, io, io).
+:- mode spawn_context_2(pred(in, di, uo) is cc_multi, out, out, di, uo)
+ is cc_multi.
+
+spawn_context_2(_, no, "", !IO) :-
+ cc_multi_equal(!IO).
:- pragma foreign_proc("C",
spawn_context_2(Goal::(pred(in, di, uo) is cc_multi), Success::out,
- _IO0::di, _IO::uo),
+ ThreadId::out, _IO0::di, _IO::uo),
[promise_pure, will_not_call_mercury, thread_safe, tabled_for_io,
may_not_duplicate],
"
#if !defined(MR_HIGHLEVEL_CODE)
{
- MR_Context *ctxt;
+ MR_Context *ctxt;
+ MR_ThreadLocalMuts *tlm;
ML_incr_thread_barrier_count();
ctxt = MR_create_context(""spawn"", MR_CONTEXT_SIZE_REGULAR, NULL);
ctxt->MR_ctxt_resume = MR_ENTRY(mercury__thread__spawn_begin_thread);
+ tlm = MR_clone_thread_local_mutables(MR_THREAD_LOCAL_MUTABLES);
+ ctxt->MR_ctxt_thread_local_mutables = tlm;
+
/*
- ** Store the closure on the top of the new context's stack.
+ ** Derive a thread id from the address of the thread-local mutable vector
+ ** for the Mercury thread. It should actually be more unique than a
+ ** context address as contexts are kept around and reused.
*/
+ ThreadId = MR_make_string(MR_ALLOC_ID, ""%p"", tlm);
+
+ /*
+ ** Store Goal and ThreadId on the top of the new context's stack.
+ */
+ ctxt->MR_ctxt_sp[0] = Goal;
+ ctxt->MR_ctxt_sp[-1] = (MR_Word) ThreadId;
- *(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);
Success = MR_TRUE;
@@ -242,6 +258,7 @@ spawn_context(Goal, Res, !IO) :-
#else /* MR_HIGHLEVEL_CODE */
{
Success = MR_FALSE;
+ ThreadId = MR_make_string_const("""");
}
#endif /* MR_HIGHLEVEL_CODE */
").
@@ -249,26 +266,28 @@ spawn_context(Goal, Res, !IO) :-
%-----------------------------------------------------------------------------%
spawn_native(Goal, Res, !IO) :-
- spawn_native_2(Goal, Success, !IO),
+ spawn_native_2(Goal, Success, ThreadId, !IO),
(
Success = yes,
- Res = ok(thread)
+ Res = ok(thread(ThreadId))
;
Success = no,
Res = error("Unable to create native thread.")
).
-:- pred spawn_native_2(pred(thread, io, io), bool, io, io).
-:- mode spawn_native_2(pred(in, di, uo) is cc_multi, out, di, uo) is cc_multi.
+:- pred spawn_native_2(pred(thread, io, io), bool, thread_id, io, io).
+:- mode spawn_native_2(pred(in, di, uo) is cc_multi, out, out, di, uo)
+ is cc_multi.
:- pragma foreign_proc("C",
spawn_native_2(Goal::(pred(in, di, uo) is cc_multi), Success::out,
- _IO0::di, _IO::uo),
+ ThreadId::out, _IO0::di, _IO::uo),
[promise_pure, will_not_call_mercury, thread_safe, tabled_for_io,
may_not_duplicate],
"
+ ThreadId = MR_make_string_const("""");
#ifdef MR_THREAD_SAFE
- Success = ML_create_exclusive_thread(Goal);
+ Success = ML_create_exclusive_thread(Goal, &ThreadId);
#else
Success = MR_FALSE;
#endif
@@ -276,7 +295,7 @@ spawn_native(Goal, Res, !IO) :-
:- pragma foreign_proc("C#",
spawn_native_2(Goal::(pred(in, di, uo) is cc_multi), Success::out,
- _IO0::di, _IO::uo),
+ ThreadId::out, _IO0::di, _IO::uo),
[promise_pure, will_not_call_mercury, thread_safe, tabled_for_io,
may_not_duplicate],
"
@@ -284,22 +303,27 @@ spawn_native(Goal, Res, !IO) :-
object[] thread_locals = runtime.ThreadLocalMutables.clone();
MercuryThread mt = new MercuryThread(Goal, thread_locals);
System.Threading.Thread thread = new System.Threading.Thread(
- new System.Threading.ThreadStart(mt.execute_goal));
+ new System.Threading.ThreadStart(mt.run));
+ ThreadId = thread.ManagedThreadId.ToString();
+ mt.setThreadId(ThreadId);
thread.Start();
Success = mr_bool.YES;
} catch (System.Threading.ThreadStartException e) {
Success = mr_bool.NO;
+ ThreadId = """";
}
").
:- pragma foreign_proc("Java",
spawn_native_2(Goal::(pred(in, di, uo) is cc_multi), Success::out,
- _IO0::di, _IO::uo),
+ ThreadId::out, _IO0::di, _IO::uo),
[promise_pure, will_not_call_mercury, thread_safe, tabled_for_io,
may_not_duplicate],
"
- MercuryThread mt = new MercuryThread((Object[]) Goal);
- Thread thread = new Thread(mt);
+ final MercuryThread mt = new MercuryThread((Object[]) Goal);
+ final Thread thread = new Thread(mt);
+ ThreadId = String.valueOf(thread.getId());
+ mt.setThreadId(ThreadId);
thread.start();
Success = bool.YES;
").
@@ -384,7 +408,8 @@ INIT mercury_sys_init_thread_modules
MR_define_entry(mercury__thread__spawn_begin_thread);
{
/* Call the closure placed the top of the stack. */
- MR_r1 = *MR_sp;
+ MR_r1 = MR_stackvar(1); /* Goal */
+ MR_r2 = MR_stackvar(2); /* ThreadId */
MR_noprof_call(MR_ENTRY(mercury__do_call_closure_1),
MR_LABEL(mercury__thread__spawn_end_thread));
}
@@ -444,7 +469,7 @@ INIT mercury_sys_init_thread_modules
#if defined(MR_THREAD_SAFE)
#include <pthread.h>
- MR_bool ML_create_exclusive_thread(MR_Word goal);
+ MR_bool ML_create_exclusive_thread(MR_Word goal, MR_String *thread_id);
void *ML_exclusive_thread_wrapper(void *arg);
typedef struct ML_ThreadWrapperArgs ML_ThreadWrapperArgs;
@@ -453,13 +478,14 @@ INIT mercury_sys_init_thread_modules
MR_Word goal;
MR_ThreadLocalMuts *thread_local_mutables;
MR_bool thread_started;
+ MR_String thread_id;
};
#endif /* MR_THREAD_SAFE */
").
:- pragma foreign_code("C", "
#if defined(MR_THREAD_SAFE)
- MR_bool ML_create_exclusive_thread(MR_Word goal)
+ MR_bool ML_create_exclusive_thread(MR_Word goal, MR_String *thread_id)
{
ML_ThreadWrapperArgs args;
pthread_t thread;
@@ -473,6 +499,7 @@ INIT mercury_sys_init_thread_modules
args.thread_local_mutables =
MR_clone_thread_local_mutables(MR_THREAD_LOCAL_MUTABLES);
args.thread_started = MR_FALSE;
+ args.thread_id = NULL;
pthread_attr_init(&attrs);
pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
@@ -486,6 +513,7 @@ INIT mercury_sys_init_thread_modules
sem_destroy(&args.sem);
if (args.thread_started) {
+ *thread_id = args.thread_id;
return MR_TRUE;
}
@@ -497,6 +525,7 @@ INIT mercury_sys_init_thread_modules
{
ML_ThreadWrapperArgs *args = arg;
MR_Word goal;
+ MR_String thread_id;
if (MR_init_thread(MR_use_now) == MR_FALSE) {
args->thread_started = MR_FALSE;
@@ -514,14 +543,18 @@ INIT mercury_sys_init_thread_modules
MR_assert(MR_THREAD_LOCAL_MUTABLES == NULL);
MR_SET_THREAD_LOCAL_MUTABLES(args->thread_local_mutables);
+ thread_id = MR_make_string(MR_ALLOC_SITE_RUNTIME,
+ ""%"" MR_INTEGER_LENGTH_MODIFIER ""x"", MR_SELF_THREAD_ID);
+
/*
** Take a copy of the goal before telling the parent we are ready.
*/
goal = args->goal;
args->thread_started = MR_TRUE;
+ args->thread_id = thread_id;
MR_SEM_POST(&args->sem, ""ML_exclusive_thread_wrapper"");
- ML_call_back_to_mercury_cc_multi(goal);
+ ML_call_back_to_mercury_cc_multi(goal, thread_id);
MR_finalize_thread_engine();
@@ -532,20 +565,21 @@ INIT mercury_sys_init_thread_modules
#endif /* MR_THREAD_SAFE */
").
-:- pred call_back_to_mercury(pred(thread, io, io), io, io).
-:- mode call_back_to_mercury(pred(in, di, uo) is cc_multi, di, uo) is cc_multi.
+:- pred call_back_to_mercury(pred(thread, io, io), thread_id, io, io).
+:- mode call_back_to_mercury(pred(in, di, uo) is cc_multi, in, di, uo)
+ is cc_multi.
:- pragma foreign_export("C",
- call_back_to_mercury(pred(in, di, uo) is cc_multi, di, uo),
+ call_back_to_mercury(pred(in, di, uo) is cc_multi, in, di, uo),
"ML_call_back_to_mercury_cc_multi").
:- pragma foreign_export("C#",
- call_back_to_mercury(pred(in, di, uo) is cc_multi, di, uo),
+ call_back_to_mercury(pred(in, di, uo) is cc_multi, in, di, uo),
"ML_call_back_to_mercury_cc_multi").
:- pragma foreign_export("Java",
- call_back_to_mercury(pred(in, di, uo) is cc_multi, di, uo),
+ call_back_to_mercury(pred(in, di, uo) is cc_multi, in, di, uo),
"ML_call_back_to_mercury_cc_multi").
-call_back_to_mercury(Goal, !IO) :-
- Goal(thread, !IO).
+call_back_to_mercury(Goal, ThreadId, !IO) :-
+ Goal(thread(ThreadId), !IO).
%-----------------------------------------------------------------------------%
@@ -598,35 +632,47 @@ call_back_to_mercury(Goal, !IO) :-
%-----------------------------------------------------------------------------%
:- pragma foreign_code("C#", "
-public class MercuryThread {
- object[] Goal;
- object[] thread_local_mutables;
+private class MercuryThread {
+ private object[] Goal;
+ private object[] thread_local_mutables;
+ private string ThreadId;
- public MercuryThread(object[] g, object[] tlmuts)
+ internal MercuryThread(object[] g, object[] tlmuts)
{
Goal = g;
thread_local_mutables = tlmuts;
}
- public void execute_goal()
+ internal void setThreadId(string id)
+ {
+ ThreadId = id;
+ }
+
+ internal void run()
{
runtime.ThreadLocalMutables.set_array(thread_local_mutables);
- thread.ML_call_back_to_mercury_cc_multi(Goal);
+ thread.ML_call_back_to_mercury_cc_multi(Goal, ThreadId);
}
}").
:- pragma foreign_code("Java", "
-public static class MercuryThread implements Runnable {
- final Object[] Goal;
+private static class MercuryThread implements Runnable {
+ private final Object[] Goal;
+ private String ThreadId;
- public MercuryThread(Object[] g)
+ private MercuryThread(Object[] g)
{
Goal = g;
}
+ private void setThreadId(String id)
+ {
+ ThreadId = id;
+ }
+
public void run()
{
- thread.ML_call_back_to_mercury_cc_multi(Goal);
+ thread.ML_call_back_to_mercury_cc_multi(Goal, ThreadId);
}
}").
More information about the reviews
mailing list