[m-rev.] for review: Add thread.spawn_native/5 with minimum stack size option.
Peter Wang
novalazy at gmail.com
Tue Oct 26 13:18:34 AEDT 2021
(diff generated with -b)
library/thread.m:
Add thread_options type, and a variant of the spawn_native predicate
that takes a thread_options argument.
The only thread option supported so far is to request a minimum
stack size for the newly created thread. This is only implemented
for POSIX threads so far.
NEWS:
Announce changes.
diff --git a/NEWS b/NEWS
index 68c1db24e..3a07b8fd8 100644
--- a/NEWS
+++ b/NEWS
@@ -352,6 +352,14 @@ Changes to the Mercury standard library
- pred `apply_rec_substitution_to_list/3`
(replacement: `apply_rec_substitution_in_terms/3`)
+### Changes to the `thread` module
+
+* The following predicate and functions have been added:
+
+ - func `init_thread_options/0`
+ - pred `set_min_stack_size/3`
+ - pred `spawn_native/5`
+
### Changes to the `thread.mvar` module
* The following obsolete function has been removed:
diff --git a/library/thread.m b/library/thread.m
index 401ab8ab7..7f70e5d4b 100644
--- a/library/thread.m
+++ b/library/thread.m
@@ -3,7 +3,7 @@
%---------------------------------------------------------------------------%
% Copyright (C) 2000-2001, 2003-2004, 2006-2008, 2010-2011 The University
% of Melbourne.
-% Copyright (C) 2014-2018 The Mercury Team.
+% Copyright (C) 2014-2021 The Mercury Team.
% This file is distributed under the terms specified in COPYING.LIB.
%---------------------------------------------------------------------------%
%
@@ -67,7 +67,31 @@
:- pred spawn(pred(thread, io, io), maybe_error(thread), io, io).
:- mode spawn(pred(in, di, uo) is cc_multi, out, di, uo) is cc_multi.
- % spawn_native(Closure, Res, IO0, IO):
+ % A type representing options that affect thread creation.
+ %
+:- type thread_options.
+
+ % Create a new thread options object.
+ %
+:- func init_thread_options = thread_options.
+
+ % Set the minimum stack size (in bytes) for a new thread created with these
+ % thread options. Only affects POSIX threads backend. The Java and C#
+ % backends do not yet respect the minimum stack size option.
+ %
+ % The special value 0 means to use the default stack size of the underlying
+ % environment.
+ %
+:- pred set_min_stack_size(uint::in, thread_options::in, thread_options::out)
+ is det.
+
+ % spawn_native(Closure, Res, !IO):
+ % Same as spawn_native(Closure, init_thread_options, Res, !IO).
+ %
+:- pred spawn_native(pred(thread, io, io), maybe_error(thread), io, io).
+:- mode spawn_native(pred(in, di, uo) is cc_multi, out, di, uo) is cc_multi.
+
+ % spawn_native(Closure, Options, Res, IO0, IO):
% Like spawn/4, but Closure will be performed in a separate "native thread"
% of the environment the program is running in (POSIX thread, Windows
% thread, Java thread, etc.).
@@ -81,8 +105,10 @@
% Also, some foreign code depends on OS thread-local state so needs to be
% consistently executed on a dedicated OS thread to be usable.
%
-:- pred spawn_native(pred(thread, io, io), maybe_error(thread), io, io).
-:- mode spawn_native(pred(in, di, uo) is cc_multi, out, di, uo) is cc_multi.
+:- pred spawn_native(pred(thread, io, io), thread_options, maybe_error(thread),
+ io, io).
+:- mode spawn_native(pred(in, di, uo) is cc_multi, in, out,
+ di, uo) is cc_multi.
% yield(IO0, IO) is logically equivalent to (IO = IO0) but
% operationally, yields the Mercury engine to some other thread
@@ -141,6 +167,11 @@ import jmercury.runtime.JavaInternal;
import jmercury.runtime.Task;
").
+:- type thread_options
+ ---> thread_options(
+ min_stack_size :: uint
+ ).
+
% The thread id is not formally exposed yet but allows different thread
% handles to compare unequal.
%
@@ -301,8 +332,19 @@ spawn_context_2(_, Res, "", !IO) :-
%---------------------------------------------------------------------------%
+init_thread_options = thread_options(0u).
+
+set_min_stack_size(MinStackSize, !Options) :-
+ !Options ^ min_stack_size := MinStackSize.
+
+%---------------------------------------------------------------------------%
+
spawn_native(Goal, Res, !IO) :-
- spawn_native_2(Goal, Success, ThreadId, ErrorMsg, !IO),
+ spawn_native(Goal, init_thread_options, Res, !IO).
+
+spawn_native(Goal, Options, Res, !IO) :-
+ Options = thread_options(MinStackSize),
+ spawn_native_2(Goal, MinStackSize, Success, ThreadId, ErrorMsg, !IO),
(
Success = yes,
Res = ok(thread(ThreadId))
@@ -311,19 +353,20 @@ spawn_native(Goal, Res, !IO) :-
Res = error(ErrorMsg)
).
-:- pred spawn_native_2(pred(thread, io, io), bool, thread_id, string, io, io).
-:- mode spawn_native_2(pred(in, di, uo) is cc_multi, out, out, out, di, uo)
- is cc_multi.
+:- pred spawn_native_2(pred(thread, io, io), uint, bool, thread_id, string,
+ io, io).
+:- mode spawn_native_2(pred(in, di, uo) is cc_multi, in, out, out, out,
+ di, uo) is cc_multi.
:- pragma foreign_proc("C",
- spawn_native_2(Goal::(pred(in, di, uo) is cc_multi), Success::out,
- ThreadId::out, ErrorMsg::out, _IO0::di, _IO::uo),
+ spawn_native_2(Goal::(pred(in, di, uo) is cc_multi), MinStackSize::in,
+ Success::out, ThreadId::out, ErrorMsg::out, _IO0::di, _IO::uo),
[promise_pure, will_not_call_mercury, thread_safe, tabled_for_io,
may_not_duplicate],
"
#ifdef MR_THREAD_SAFE
- Success = ML_create_exclusive_thread(Goal, &ThreadId, &ErrorMsg,
- MR_ALLOC_ID);
+ Success = ML_create_exclusive_thread(Goal, MinStackSize, &ThreadId,
+ &ErrorMsg, MR_ALLOC_ID);
#else
Success = MR_FALSE;
ThreadId = MR_make_string_const("""");
@@ -333,8 +376,8 @@ spawn_native(Goal, Res, !IO) :-
").
:- pragma foreign_proc("C#",
- spawn_native_2(Goal::(pred(in, di, uo) is cc_multi), Success::out,
- ThreadId::out, ErrorMsg::out, _IO0::di, _IO::uo),
+ spawn_native_2(Goal::(pred(in, di, uo) is cc_multi), _MinStackSize::in,
+ Success::out, ThreadId::out, ErrorMsg::out, _IO0::di, _IO::uo),
[promise_pure, will_not_call_mercury, thread_safe, tabled_for_io,
may_not_duplicate],
"
@@ -361,8 +404,8 @@ spawn_native(Goal, Res, !IO) :-
").
:- pragma foreign_proc("Java",
- spawn_native_2(Goal::(pred(in, di, uo) is cc_multi), Success::out,
- ThreadId::out, ErrorMsg::out, _IO0::di, _IO::uo),
+ spawn_native_2(Goal::(pred(in, di, uo) is cc_multi), _MinStackSize::in,
+ Success::out, ThreadId::out, ErrorMsg::out, _IO0::di, _IO::uo),
[promise_pure, will_not_call_mercury, thread_safe, tabled_for_io,
may_not_duplicate],
"
@@ -527,8 +570,8 @@ INIT mercury_sys_init_thread_modules
#include <pthread.h>
static MR_bool ML_create_exclusive_thread(MR_Word goal,
- MR_String *thread_id, MR_String *error_msg,
- MR_AllocSiteInfoPtr alloc_id);
+ size_t min_stack_size, MR_String *thread_id,
+ MR_String *error_msg, MR_AllocSiteInfoPtr alloc_id);
static void *ML_exclusive_thread_wrapper(void *arg);
typedef struct ML_ThreadWrapperArgs ML_ThreadWrapperArgs;
@@ -553,14 +596,14 @@ INIT mercury_sys_init_thread_modules
:- pragma foreign_code("C", "
#if defined(MR_THREAD_SAFE)
static MR_bool
- ML_create_exclusive_thread(MR_Word goal, MR_String *thread_id,
- MR_String *error_msg, MR_AllocSiteInfoPtr alloc_id)
+ ML_create_exclusive_thread(MR_Word goal, size_t min_stack_size,
+ MR_String *thread_id, MR_String *error_msg,
+ MR_AllocSiteInfoPtr alloc_id)
{
ML_ThreadWrapperArgs args;
pthread_t thread;
pthread_attr_t attrs;
- int thread_err;
- int thread_errno;
+ int err;
char errbuf[MR_STRERROR_BUF_SIZE];
*thread_id = MR_make_string_const("""");
@@ -583,22 +626,36 @@ INIT mercury_sys_init_thread_modules
args.thread_id = NULL;
pthread_attr_init(&attrs);
- pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
- thread_err = pthread_create(&thread, &attrs, ML_exclusive_thread_wrapper,
- &args);
- thread_errno = errno;
- pthread_attr_destroy(&attrs);
+ err = pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
+ if (err != 0) {
+ *error_msg = MR_make_string(alloc_id,
+ ""pthread_attr_setdetachstate failed: %s"",
+ MR_strerror(errno, errbuf, sizeof(errbuf)));
+ goto failed_to_create_thread;
+ }
+ if (min_stack_size > 0) {
+ err = pthread_attr_setstacksize(&attrs, min_stack_size);
+ if (err != 0) {
+ *error_msg = MR_make_string(alloc_id,
+ ""pthread_attr_setstacksize failed: %s"",
+ MR_strerror(errno, errbuf, sizeof(errbuf)));
+ goto failed_to_create_thread;
+ }
+ }
- if (thread_err != 0) {
+ err = pthread_create(&thread, &attrs, ML_exclusive_thread_wrapper, &args);
+ if (err != 0) {
*error_msg = MR_make_string(alloc_id, ""pthread_create failed: %s"",
- MR_strerror(thread_errno, errbuf, sizeof(errbuf)));
- } else {
+ MR_strerror(errno, errbuf, sizeof(errbuf)));
+ goto failed_to_create_thread;
+ }
+
MR_LOCK(&args.mutex, ""ML_create_exclusive_thread"");
while (args.thread_state == ML_THREAD_NOT_READY) {
- int cond_err = MR_COND_WAIT(&args.cond, &args.mutex,
+ err = MR_COND_WAIT(&args.cond, &args.mutex,
""ML_create_exclusive_thread"");
// EINTR should not be possible, but it has happened before.
- if (cond_err != 0 && errno != EINTR) {
+ if (err != 0 && errno != EINTR) {
MR_fatal_error(
""ML_create_exclusive_thread: MR_COND_WAIT error: %s"",
MR_strerror(errno, errbuf, sizeof(errbuf)));
@@ -610,8 +667,9 @@ INIT mercury_sys_init_thread_modules
*error_msg =
MR_make_string_const(""Error setting up engine for thread."");
}
- }
+failed_to_create_thread:
+ pthread_attr_destroy(&attrs);
pthread_cond_destroy(&args.cond);
pthread_mutex_destroy(&args.mutex);
--
2.33.1
More information about the reviews
mailing list