From aea1f59f6ea3b383324f836fee9e5625a6aaee80 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Sat, 17 Jul 2021 15:13:28 -0500 Subject: [PATCH] Add option to build janet without thread library. --- CHANGELOG.md | 1 + meson.build | 1 + meson_options.txt | 1 + src/conf/janetconf.h | 1 + src/core/ev.c | 29 +++++++++++++++++++++++------ src/include/janet.h | 10 ++++++++-- 6 files changed, 35 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f0a85f0..0b19d8a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ All notable changes to this project will be documented in this file. ## 1.17.0 - Unreleased +- Add build option to disable the threading library without disabling all threads. - Remove JPM from the main Janet distribution. Instead, JPM must be installed separately like any other package. - Fix issue with `ev/go` when called with an initial value and supervisor. diff --git a/meson.build b/meson.build index ff6cda15..55511b35 100644 --- a/meson.build +++ b/meson.build @@ -73,6 +73,7 @@ conf.set('JANET_NO_REALPATH', not get_option('realpath')) conf.set('JANET_NO_PROCESSES', not get_option('processes')) conf.set('JANET_SIMPLE_GETLINE', get_option('simple_getline')) conf.set('JANET_EV_EPOLL', get_option('epoll')) +conf.set('JANET_NO_THREADS', get_option('threads')) if get_option('os_name') != '' conf.set('JANET_OS_NAME', get_option('os_name')) endif diff --git a/meson_options.txt b/meson_options.txt index c19f662b..7d1c0e01 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,6 +1,7 @@ option('git_hash', type : 'string', value : 'meson') option('single_threaded', type : 'boolean', value : false) +option('threads', type : 'boolean', value : true) option('nanbox', type : 'boolean', value : true) option('dynamic_modules', type : 'boolean', value : true) option('docstrings', type : 'boolean', value : true) diff --git a/src/conf/janetconf.h b/src/conf/janetconf.h index 097017db..cd143c83 100644 --- a/src/conf/janetconf.h +++ b/src/conf/janetconf.h @@ -32,6 +32,7 @@ /* #define JANET_NO_REALPATH */ /* #define JANET_NO_SYMLINKS */ /* #define JANET_NO_UMASK */ +/* #define JANET_NO_THREADS */ /* Other settings */ /* #define JANET_DEBUG */ diff --git a/src/core/ev.c b/src/core/ev.c index 93381bf7..e5da6ed3 100644 --- a/src/core/ev.c +++ b/src/core/ev.c @@ -55,8 +55,6 @@ #endif #endif -/* Ring buffer for storing a list of fibers */ - typedef struct { JanetFiber *fiber; uint32_t sched_id; @@ -688,7 +686,7 @@ static int janet_channel_push(JanetChannel *channel, Janet x, int mode) { return 0; } -/* Pop from a channel - returns 1 if item was obtain, 0 otherwise. The item +/* Pop from a channel - returns 1 if item was obtained, 0 otherwise. The item * is returned by reference. If the pop would block, will add to the read_pending * queue in the channel. */ static int janet_channel_pop(JanetChannel *channel, Janet *item, int is_choice) { @@ -1386,6 +1384,9 @@ void janet_ev_threaded_call(JanetThreadedSubroutine fp, JanetEVGenericMessage ar /* Default callback for janet_ev_threaded_await. */ void janet_ev_default_threaded_callback(JanetEVGenericMessage return_value) { + if (return_value.fiber == NULL) { + return; + } switch (return_value.tag) { default: case JANET_EV_TCTAG_NIL: @@ -2052,7 +2053,11 @@ static JanetEVGenericMessage janet_go_thread_subr(JanetEVGenericMessage args) { static Janet cfun_ev_thread(int32_t argc, Janet *argv) { janet_arity(argc, 1, 3); janet_getfiber(argv, 0); - Janet value = argc == 2 ? argv[1] : janet_wrap_nil(); + Janet value = argc >= 2 ? argv[1] : janet_wrap_nil(); + uint64_t flags = 0; + if (argc >= 3) { + flags = janet_getflags(argv, 2, "n"); + } /* Marshal arguments for the new thread. */ JanetBuffer *buffer = janet_malloc(sizeof(JanetBuffer)); if (NULL == buffer) { @@ -2063,7 +2068,18 @@ static Janet cfun_ev_thread(int32_t argc, Janet *argv) { janet_marshal(buffer, janet_wrap_table(janet_vm.registry), NULL, JANET_MARSHAL_UNSAFE); janet_marshal(buffer, argv[0], NULL, JANET_MARSHAL_UNSAFE); janet_marshal(buffer, value, NULL, JANET_MARSHAL_UNSAFE); - janet_ev_threaded_await(janet_go_thread_subr, 0, argc, buffer); + if (flags & 0x1) { + /* Return immediately */ + JanetEVGenericMessage arguments; + arguments.tag = 0; + arguments.argi = argc; + arguments.argp = buffer; + arguments.fiber = NULL; + janet_ev_threaded_call(janet_go_thread_subr, arguments, janet_ev_default_threaded_callback); + return janet_wrap_nil(); + } else { + janet_ev_threaded_await(janet_go_thread_subr, 0, argc, buffer); + } } static Janet cfun_ev_give_supervisor(int32_t argc, Janet *argv) { @@ -2185,7 +2201,8 @@ static const JanetReg ev_cfuns[] = { "Resume a (copy of a) `fiber` in a new operating system thread, optionally passing `value` " "to resume with. " "Unlike `ev/go`, this function will suspend the current fiber until the thread is complete. " - "The the final result.") + "If you want to run the thread without waiting for a result, pass the `:n` flag to return nil immediately. " + "Otherwise, returns (a copy of) the final result from the fiber on the new thread.") }, { "ev/give-supervisor", cfun_ev_give_supervisor, diff --git a/src/include/janet.h b/src/include/janet.h index f07074dd..8573772a 100644 --- a/src/include/janet.h +++ b/src/include/janet.h @@ -144,17 +144,23 @@ extern "C" { #define JANET_NO_UTC_MKTIME #endif +/* Check thread library */ +#ifndef JANET_NO_THREADS +#define JANET_THREADS +#endif + /* Define how global janet state is declared */ +/* Also enable the thread library only if not single-threaded */ #ifdef JANET_SINGLE_THREADED #define JANET_THREAD_LOCAL +#undef JANET_THREADS #elif defined(__GNUC__) #define JANET_THREAD_LOCAL __thread -#define JANET_THREADS #elif defined(_MSC_BUILD) #define JANET_THREAD_LOCAL __declspec(thread) -#define JANET_THREADS #else #define JANET_THREAD_LOCAL +#undef JANET_THREADS #endif /* Enable or disable dynamic module loading. Enabled by default. */