@nocobase/plugin-workflow-javascript 2.1.0-beta.11 → 2.1.0-beta.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/externalVersion.js +4 -4
- package/dist/node_modules/isolated-vm/.clang-tidy +13 -0
- package/dist/node_modules/isolated-vm/.dockerignore +9 -0
- package/dist/node_modules/isolated-vm/Dockerfile.alpine +9 -0
- package/dist/node_modules/isolated-vm/Dockerfile.debian +12 -0
- package/dist/node_modules/isolated-vm/LICENSE +13 -0
- package/dist/node_modules/isolated-vm/binding.gyp +120 -0
- package/dist/node_modules/isolated-vm/include.js +3 -0
- package/dist/node_modules/isolated-vm/inspector-example.js +59 -0
- package/dist/node_modules/isolated-vm/isolated-vm.d.ts +820 -0
- package/dist/node_modules/isolated-vm/isolated-vm.js +1 -0
- package/dist/node_modules/isolated-vm/native-example/binding.gyp +23 -0
- package/dist/node_modules/isolated-vm/native-example/example.cc +61 -0
- package/dist/node_modules/isolated-vm/native-example/package.json +13 -0
- package/dist/node_modules/isolated-vm/native-example/usage.js +35 -0
- package/dist/node_modules/isolated-vm/out/isolated_vm.node +0 -0
- package/dist/node_modules/isolated-vm/package.json +1 -0
- package/dist/node_modules/isolated-vm/src/external_copy/error.h +33 -0
- package/dist/node_modules/isolated-vm/src/external_copy/external_copy.cc +509 -0
- package/dist/node_modules/isolated-vm/src/external_copy/external_copy.h +117 -0
- package/dist/node_modules/isolated-vm/src/external_copy/serializer.cc +85 -0
- package/dist/node_modules/isolated-vm/src/external_copy/serializer.h +136 -0
- package/dist/node_modules/isolated-vm/src/external_copy/serializer_nortti.cc +73 -0
- package/dist/node_modules/isolated-vm/src/external_copy/string.cc +124 -0
- package/dist/node_modules/isolated-vm/src/external_copy/string.h +28 -0
- package/dist/node_modules/isolated-vm/src/isolate/allocator.h +32 -0
- package/dist/node_modules/isolated-vm/src/isolate/allocator_nortti.cc +142 -0
- package/dist/node_modules/isolated-vm/src/isolate/class_handle.h +334 -0
- package/dist/node_modules/isolated-vm/src/isolate/cpu_profile_manager.cc +220 -0
- package/dist/node_modules/isolated-vm/src/isolate/cpu_profile_manager.h +100 -0
- package/dist/node_modules/isolated-vm/src/isolate/environment.cc +626 -0
- package/dist/node_modules/isolated-vm/src/isolate/environment.h +381 -0
- package/dist/node_modules/isolated-vm/src/isolate/executor.cc +198 -0
- package/dist/node_modules/isolated-vm/src/isolate/executor.h +183 -0
- package/dist/node_modules/isolated-vm/src/isolate/external.h +64 -0
- package/dist/node_modules/isolated-vm/src/isolate/functor_runners.h +97 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/array.h +145 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/callbacks.h +272 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/error.h +140 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/extract_params.h +145 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/handle_cast.h +257 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/read_option.h +47 -0
- package/dist/node_modules/isolated-vm/src/isolate/holder.cc +88 -0
- package/dist/node_modules/isolated-vm/src/isolate/holder.h +63 -0
- package/dist/node_modules/isolated-vm/src/isolate/inspector.cc +200 -0
- package/dist/node_modules/isolated-vm/src/isolate/inspector.h +70 -0
- package/dist/node_modules/isolated-vm/src/isolate/node_wrapper.h +15 -0
- package/dist/node_modules/isolated-vm/src/isolate/platform_delegate.cc +22 -0
- package/dist/node_modules/isolated-vm/src/isolate/platform_delegate.h +46 -0
- package/dist/node_modules/isolated-vm/src/isolate/remote_handle.h +164 -0
- package/dist/node_modules/isolated-vm/src/isolate/run_with_timeout.h +171 -0
- package/dist/node_modules/isolated-vm/src/isolate/runnable.h +29 -0
- package/dist/node_modules/isolated-vm/src/isolate/scheduler.cc +191 -0
- package/dist/node_modules/isolated-vm/src/isolate/scheduler.h +165 -0
- package/dist/node_modules/isolated-vm/src/isolate/specific.h +35 -0
- package/dist/node_modules/isolated-vm/src/isolate/stack_trace.cc +219 -0
- package/dist/node_modules/isolated-vm/src/isolate/stack_trace.h +24 -0
- package/dist/node_modules/isolated-vm/src/isolate/strings.h +127 -0
- package/dist/node_modules/isolated-vm/src/isolate/three_phase_task.cc +385 -0
- package/dist/node_modules/isolated-vm/src/isolate/three_phase_task.h +136 -0
- package/dist/node_modules/isolated-vm/src/isolate/transferable.h +15 -0
- package/dist/node_modules/isolated-vm/src/isolate/util.h +45 -0
- package/dist/node_modules/isolated-vm/src/isolate/v8_inspector_wrapper.h +12 -0
- package/dist/node_modules/isolated-vm/src/isolate/v8_version.h +12 -0
- package/dist/node_modules/isolated-vm/src/isolated_vm.h +71 -0
- package/dist/node_modules/isolated-vm/src/lib/covariant.h +50 -0
- package/dist/node_modules/isolated-vm/src/lib/lockable.h +178 -0
- package/dist/node_modules/isolated-vm/src/lib/suspend.h +106 -0
- package/dist/node_modules/isolated-vm/src/lib/thread_pool.cc +98 -0
- package/dist/node_modules/isolated-vm/src/lib/thread_pool.h +45 -0
- package/dist/node_modules/isolated-vm/src/lib/timer.cc +233 -0
- package/dist/node_modules/isolated-vm/src/lib/timer.h +36 -0
- package/dist/node_modules/isolated-vm/src/module/callback.cc +151 -0
- package/dist/node_modules/isolated-vm/src/module/callback.h +64 -0
- package/dist/node_modules/isolated-vm/src/module/context_handle.cc +241 -0
- package/dist/node_modules/isolated-vm/src/module/context_handle.h +35 -0
- package/dist/node_modules/isolated-vm/src/module/evaluation.cc +109 -0
- package/dist/node_modules/isolated-vm/src/module/evaluation.h +99 -0
- package/dist/node_modules/isolated-vm/src/module/external_copy_handle.cc +119 -0
- package/dist/node_modules/isolated-vm/src/module/external_copy_handle.h +64 -0
- package/dist/node_modules/isolated-vm/src/module/isolate.cc +136 -0
- package/dist/node_modules/isolated-vm/src/module/isolate_handle.cc +611 -0
- package/dist/node_modules/isolated-vm/src/module/isolate_handle.h +47 -0
- package/dist/node_modules/isolated-vm/src/module/lib_handle.cc +77 -0
- package/dist/node_modules/isolated-vm/src/module/lib_handle.h +28 -0
- package/dist/node_modules/isolated-vm/src/module/module_handle.cc +475 -0
- package/dist/node_modules/isolated-vm/src/module/module_handle.h +68 -0
- package/dist/node_modules/isolated-vm/src/module/native_module_handle.cc +104 -0
- package/dist/node_modules/isolated-vm/src/module/native_module_handle.h +49 -0
- package/dist/node_modules/isolated-vm/src/module/reference_handle.cc +636 -0
- package/dist/node_modules/isolated-vm/src/module/reference_handle.h +106 -0
- package/dist/node_modules/isolated-vm/src/module/script_handle.cc +107 -0
- package/dist/node_modules/isolated-vm/src/module/script_handle.h +37 -0
- package/dist/node_modules/isolated-vm/src/module/session_handle.cc +173 -0
- package/dist/node_modules/isolated-vm/src/module/session_handle.h +31 -0
- package/dist/node_modules/isolated-vm/src/module/transferable.cc +268 -0
- package/dist/node_modules/isolated-vm/src/module/transferable.h +42 -0
- package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v18.0.0.h +360 -0
- package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v18.3.0.h +376 -0
- package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v20.0.0.h +397 -0
- package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v22.0.0.h +419 -0
- package/dist/node_modules/winston-transport/package.json +1 -1
- package/dist/server/IsolatedVm.js +75 -0
- package/dist/server/ScriptInstruction.d.ts +6 -0
- package/dist/server/ScriptInstruction.js +11 -1
- package/dist/server/Vm.js +42 -27
- package/package.json +3 -2
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include "node_wrapper.h"
|
|
3
|
+
#include "./v8_version.h"
|
|
4
|
+
#if V8_AT_LEAST(12, 4, 254)
|
|
5
|
+
#include "v8_inspector/nodejs_v22.0.0.h"
|
|
6
|
+
#elif V8_AT_LEAST(11, 3, 244)
|
|
7
|
+
#include "v8_inspector/nodejs_v20.0.0.h"
|
|
8
|
+
#elif V8_AT_LEAST(10, 2, 154)
|
|
9
|
+
#include "v8_inspector/nodejs_v18.3.0.h"
|
|
10
|
+
#else
|
|
11
|
+
#include "v8_inspector/nodejs_v18.0.0.h"
|
|
12
|
+
#endif
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#include "node_wrapper.h"
|
|
2
|
+
#define V8_AT_LEAST(major, minor, patch) (\
|
|
3
|
+
V8_MAJOR_VERSION > (major) || \
|
|
4
|
+
(V8_MAJOR_VERSION == (major) && V8_MINOR_VERSION > (minor)) || \
|
|
5
|
+
(V8_MAJOR_VERSION == (major) && V8_MINOR_VERSION == (minor) && V8_BUILD_NUMBER >= (patch)) \
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
#ifdef NODE_MODULE_VERSION
|
|
9
|
+
#define NODE_MODULE_OR_V8_AT_LEAST(nodejs, v8_major, v8_minor, v8_build) (NODE_MODULE_VERSION >= (nodejs))
|
|
10
|
+
#else
|
|
11
|
+
#define NODE_MODULE_OR_V8_AT_LEAST(nodejs, v8_major, v8_minor, v8_build) (V8_AT_LEAST(v8_major, v8_minor, v8_build))
|
|
12
|
+
#endif
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#ifdef _WIN32
|
|
3
|
+
#define ISOLATED_VM_MODULE extern "C" __declspec(dllexport)
|
|
4
|
+
#else
|
|
5
|
+
#define ISOLATED_VM_MODULE extern "C"
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
#include "isolate/environment.h"
|
|
9
|
+
#include "isolate/holder.h"
|
|
10
|
+
#include "isolate/remote_handle.h"
|
|
11
|
+
#include "isolate/runnable.h"
|
|
12
|
+
#include <memory>
|
|
13
|
+
|
|
14
|
+
namespace isolated_vm {
|
|
15
|
+
using Runnable = ivm::Runnable;
|
|
16
|
+
// ^ The only thing you need to know: `virtual void Run() = 0`
|
|
17
|
+
|
|
18
|
+
class IsolateHolder {
|
|
19
|
+
private:
|
|
20
|
+
std::shared_ptr<ivm::IsolateHolder> holder;
|
|
21
|
+
explicit IsolateHolder(std::shared_ptr<ivm::IsolateHolder> holder) : holder{std::move(holder)} {
|
|
22
|
+
ivm::LockedScheduler::IncrementUvRefForIsolate(holder);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public:
|
|
26
|
+
IsolateHolder(const IsolateHolder& that) : holder{that.holder} {
|
|
27
|
+
ivm::LockedScheduler::IncrementUvRefForIsolate(holder);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
IsolateHolder(IsolateHolder&& that) noexcept : holder{std::move(that.holder)} {
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
~IsolateHolder() {
|
|
34
|
+
if (holder) {
|
|
35
|
+
ivm::LockedScheduler::DecrementUvRefForIsolate(holder);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
auto operator=(const IsolateHolder&) -> IsolateHolder& = default;
|
|
40
|
+
auto operator=(IsolateHolder&&) -> IsolateHolder& = default;
|
|
41
|
+
|
|
42
|
+
static auto GetCurrent() -> IsolateHolder {
|
|
43
|
+
return IsolateHolder{ivm::IsolateEnvironment::GetCurrentHolder()};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
void ScheduleTask(std::unique_ptr<Runnable> runnable) {
|
|
47
|
+
holder->ScheduleTask(std::move(runnable), false, true, false);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
void Release() {
|
|
51
|
+
holder.reset();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
template <typename T>
|
|
56
|
+
class RemoteHandle {
|
|
57
|
+
private:
|
|
58
|
+
std::shared_ptr<ivm::RemoteHandle<T>> handle;
|
|
59
|
+
|
|
60
|
+
public:
|
|
61
|
+
explicit RemoteHandle(v8::Local<T> handle) : handle(std::make_shared<ivm::RemoteHandle<T>>(handle)) {}
|
|
62
|
+
|
|
63
|
+
auto operator*() const {
|
|
64
|
+
return handle->Deref();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
void Release() {
|
|
68
|
+
handle.reset();
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
} // namespace isolated_vm
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#include <type_traits>
|
|
2
|
+
|
|
3
|
+
namespace detail {
|
|
4
|
+
|
|
5
|
+
template <class Base, class Type>
|
|
6
|
+
void destructor_wrapper(Base* value) {
|
|
7
|
+
static_cast<Type*>(value)->~Type();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
template <class Type, class Pack, class ...Rest>
|
|
11
|
+
struct contains_type {
|
|
12
|
+
static constexpr bool value =
|
|
13
|
+
std::is_same<Type, Pack>::value || contains_type<Type, Rest...>::value;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
template <class Type, class Pack>
|
|
17
|
+
struct contains_type<Type, Pack> : std::is_same<Type, Pack> {};
|
|
18
|
+
|
|
19
|
+
} // namespace detail
|
|
20
|
+
|
|
21
|
+
template <class Type>
|
|
22
|
+
class in_place {};
|
|
23
|
+
|
|
24
|
+
template <class Base, class ...Storage>
|
|
25
|
+
class covariant_t {
|
|
26
|
+
public:
|
|
27
|
+
template <class Ctor, class ...Args>
|
|
28
|
+
explicit covariant_t(in_place<Ctor> /*tag*/, Args&&... args) : dtor{&::detail::destructor_wrapper<Base, Ctor>} {
|
|
29
|
+
static_assert(::detail::contains_type<Ctor, Storage...>::value, "Instantiated constructor must inherit from `Base`");
|
|
30
|
+
new(&storage) Ctor(std::forward<Args>(args)...);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
~covariant_t() {
|
|
34
|
+
dtor(base());
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
covariant_t(const covariant_t&) = delete;
|
|
38
|
+
auto operator=(const covariant_t&) = delete;
|
|
39
|
+
|
|
40
|
+
auto operator*() -> auto& { return *base(); }
|
|
41
|
+
auto operator*() const -> auto& { return *base(); }
|
|
42
|
+
auto operator->() { return base(); }
|
|
43
|
+
auto operator->() const { return base(); }
|
|
44
|
+
|
|
45
|
+
private:
|
|
46
|
+
auto base() { return static_cast<Base*>(static_cast<void*>(&storage)); }
|
|
47
|
+
|
|
48
|
+
std::aligned_union_t<1, Storage...> storage;
|
|
49
|
+
void(*dtor)(Base*);
|
|
50
|
+
};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <condition_variable>
|
|
3
|
+
#include <mutex>
|
|
4
|
+
#include <shared_mutex>
|
|
5
|
+
|
|
6
|
+
namespace ivm {
|
|
7
|
+
namespace detail {
|
|
8
|
+
|
|
9
|
+
// C++17 adds mandatory return value optimization which enables returning a scoped_lock
|
|
10
|
+
#if __cplusplus >= 201700 && __cpp_lib_scoped_lock
|
|
11
|
+
template <class Mutex>
|
|
12
|
+
using scoped_lock = std::scoped_lock<Mutex>;
|
|
13
|
+
#else
|
|
14
|
+
template <class Mutex>
|
|
15
|
+
using scoped_lock = std::unique_lock<Mutex>;
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
// Detect shared mutex implementation (if any)
|
|
19
|
+
template <bool Shared>
|
|
20
|
+
struct mutex_traits_t {
|
|
21
|
+
using mutex_t = std::mutex;
|
|
22
|
+
static constexpr bool shared = false;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
template <>
|
|
26
|
+
struct mutex_traits_t<true> {
|
|
27
|
+
#if __cpp_lib_shared_mutex
|
|
28
|
+
using mutex_t = std::shared_mutex;
|
|
29
|
+
static constexpr bool shared = true;
|
|
30
|
+
#elif __cpp_lib_shared_timed_mutex && !__APPLE__
|
|
31
|
+
using mutex_t = std::shared_timed_mutex;
|
|
32
|
+
static constexpr bool shared = true;
|
|
33
|
+
#else
|
|
34
|
+
using mutex_t = std::mutex;
|
|
35
|
+
static constexpr bool shared = false;
|
|
36
|
+
#endif
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Detect lock needed for mutex + wait
|
|
40
|
+
template <class Traits, bool Waitable>
|
|
41
|
+
struct lock_traits_t;
|
|
42
|
+
|
|
43
|
+
template <class Traits>
|
|
44
|
+
struct lock_traits_t<Traits, false> {
|
|
45
|
+
using read_t = typename std::conditional<Traits::shared,
|
|
46
|
+
std::shared_lock<typename Traits::mutex_t>,
|
|
47
|
+
scoped_lock<typename Traits::mutex_t>>::type;
|
|
48
|
+
using write_t = scoped_lock<typename Traits::mutex_t>;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
template <class Traits>
|
|
52
|
+
struct lock_traits_t<Traits, true> {
|
|
53
|
+
static_assert(Traits::waitable, "Mutex is not waitable");
|
|
54
|
+
using read_t = typename std::conditional<Traits::shared,
|
|
55
|
+
std::shared_lock<typename Traits::mutex_t>,
|
|
56
|
+
std::unique_lock<typename Traits::mutex_t>>::type;
|
|
57
|
+
using write_t = std::unique_lock<typename Traits::mutex_t>;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// std::condition_variable is only good for std::unique_lock<std::mutex>
|
|
61
|
+
template <class Mutex>
|
|
62
|
+
struct condition_variable_t {
|
|
63
|
+
using type_t = std::condition_variable_any;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
template <>
|
|
67
|
+
struct condition_variable_t<std::mutex> {
|
|
68
|
+
using type_t = std::condition_variable;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Holds the lock and provides pointer semantics
|
|
72
|
+
template <class Lockable, class Lock>
|
|
73
|
+
class lock_holder_t {
|
|
74
|
+
template <bool, class> friend struct wait_impl_t;
|
|
75
|
+
|
|
76
|
+
public:
|
|
77
|
+
explicit lock_holder_t(Lockable& lockable) : lockable{lockable}, lock{lockable.mutex} {}
|
|
78
|
+
|
|
79
|
+
auto operator*() -> auto& { return lockable.resource; }
|
|
80
|
+
auto operator*() const -> auto& { return lockable.resource; }
|
|
81
|
+
auto operator->() { return &lockable.resource; }
|
|
82
|
+
auto operator->() const { return &lockable.resource; }
|
|
83
|
+
|
|
84
|
+
private:
|
|
85
|
+
Lockable& lockable;
|
|
86
|
+
Lock lock;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// `wait` implementation
|
|
90
|
+
template <bool Waitable, class Type>
|
|
91
|
+
struct wait_impl_t;
|
|
92
|
+
|
|
93
|
+
template <class Type>
|
|
94
|
+
struct wait_impl_t<false, Type> {
|
|
95
|
+
using lock_t = Type;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
template <class Type>
|
|
99
|
+
struct wait_impl_t<true, Type> {
|
|
100
|
+
class lock_t : public Type {
|
|
101
|
+
public:
|
|
102
|
+
using Type::Type;
|
|
103
|
+
void wait() {
|
|
104
|
+
wait_impl(*this);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
private:
|
|
109
|
+
template <class Lock>
|
|
110
|
+
static void wait_impl(Lock& lock) {
|
|
111
|
+
lock.lockable.cv.wait(lock.lock);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Internal `condition_variable` storage
|
|
116
|
+
template <bool Waitable, class Mutex>
|
|
117
|
+
class condition_variable_holder_t {};
|
|
118
|
+
|
|
119
|
+
template <class Mutex>
|
|
120
|
+
class condition_variable_holder_t<true, Mutex> {
|
|
121
|
+
template <bool, class> friend struct wait_impl_t;
|
|
122
|
+
|
|
123
|
+
public:
|
|
124
|
+
void notify_one() {
|
|
125
|
+
cv.notify_one();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
void notify_all() {
|
|
129
|
+
cv.notify_all();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private:
|
|
133
|
+
mutable typename condition_variable_t<Mutex>::type_t cv;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// Holds resource and mutex
|
|
137
|
+
template <class Type, class Traits>
|
|
138
|
+
class lockable_impl_t : public condition_variable_holder_t<Traits::waitable, typename Traits::mutex_t> {
|
|
139
|
+
template <class, class> friend class lock_holder_t;
|
|
140
|
+
|
|
141
|
+
public:
|
|
142
|
+
lockable_impl_t() = default;
|
|
143
|
+
template <class... Args>
|
|
144
|
+
explicit lockable_impl_t(Args&&... args) : resource{std::forward<Args>(args)...} {}
|
|
145
|
+
lockable_impl_t(const lockable_impl_t&) = delete;
|
|
146
|
+
~lockable_impl_t() = default;
|
|
147
|
+
auto operator=(const lockable_impl_t&) = delete;
|
|
148
|
+
|
|
149
|
+
template <bool Waitable = false>
|
|
150
|
+
auto read() const {
|
|
151
|
+
return typename wait_impl_t<Waitable, lock_holder_t<const lockable_impl_t, typename lock_traits_t<Traits, Waitable>::read_t>>::lock_t{*this};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
template <bool Waitable = false>
|
|
155
|
+
auto write() {
|
|
156
|
+
return typename wait_impl_t<Waitable, lock_holder_t<lockable_impl_t, typename lock_traits_t<Traits, Waitable>::write_t>>::lock_t{*this};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private:
|
|
160
|
+
Type resource{};
|
|
161
|
+
mutable typename Traits::mutex_t mutex;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Combine mutex traits and waitable traits
|
|
165
|
+
template <bool Waitable>
|
|
166
|
+
struct waitable_traits_t {
|
|
167
|
+
static constexpr bool waitable = Waitable;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
template <bool Shared, bool Waitable>
|
|
171
|
+
struct lockable_traits_t : mutex_traits_t<Shared>, waitable_traits_t<Waitable> {};
|
|
172
|
+
|
|
173
|
+
} // namespace detail
|
|
174
|
+
|
|
175
|
+
template <class Type, bool Shared = false, bool Waitable = false>
|
|
176
|
+
using lockable_t = detail::lockable_impl_t<Type, detail::lockable_traits_t<Shared, Waitable>>;
|
|
177
|
+
|
|
178
|
+
} // namespace ivm
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// Linux
|
|
4
|
+
#ifdef __linux__
|
|
5
|
+
#include <signal.h>
|
|
6
|
+
namespace ivm {
|
|
7
|
+
class thread_suspend_handle {
|
|
8
|
+
public:
|
|
9
|
+
thread_suspend_handle() :
|
|
10
|
+
id{pthread_self()},
|
|
11
|
+
prev{std::exchange(instance(), this)} {}
|
|
12
|
+
|
|
13
|
+
~thread_suspend_handle() {
|
|
14
|
+
std::exchange(instance(), prev);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
thread_suspend_handle(const thread_suspend_handle&) = delete;
|
|
18
|
+
auto operator=(thread_suspend_handle&) = delete;
|
|
19
|
+
|
|
20
|
+
void suspend() {
|
|
21
|
+
// Called from another thread
|
|
22
|
+
invoked = true;
|
|
23
|
+
pthread_kill(id, SIGRTMIN);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
struct initialize {
|
|
27
|
+
initialize() {
|
|
28
|
+
// Set process-wide signal handler
|
|
29
|
+
struct sigaction handler;
|
|
30
|
+
memset(&handler, '\0', sizeof(handler));
|
|
31
|
+
handler.sa_handler = callback;
|
|
32
|
+
sigemptyset(&handler.sa_mask);
|
|
33
|
+
assert(sigaction(SIGRTMIN, &handler, nullptr) == 0);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
private:
|
|
38
|
+
static void callback(int) {
|
|
39
|
+
if (instance() != nullptr && instance()->invoked == true) {
|
|
40
|
+
while (true) {
|
|
41
|
+
using namespace std::chrono_literals;
|
|
42
|
+
std::this_thread::sleep_for(100s);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static thread_suspend_handle*& instance() {
|
|
48
|
+
static thread_local thread_suspend_handle* instance = nullptr;
|
|
49
|
+
return instance;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
pthread_t id;
|
|
53
|
+
thread_suspend_handle* prev;
|
|
54
|
+
bool invoked = false;
|
|
55
|
+
};
|
|
56
|
+
} // namespace ivm
|
|
57
|
+
|
|
58
|
+
// macOS
|
|
59
|
+
#elif __APPLE__
|
|
60
|
+
#include <mach/mach.h>
|
|
61
|
+
namespace ivm {
|
|
62
|
+
class thread_suspend_handle {
|
|
63
|
+
public:
|
|
64
|
+
thread_suspend_handle() : id{mach_thread_self()} {}
|
|
65
|
+
~thread_suspend_handle() = default;
|
|
66
|
+
thread_suspend_handle(const thread_suspend_handle&) = delete;
|
|
67
|
+
auto operator=(thread_suspend_handle&) = delete;
|
|
68
|
+
void suspend() const { thread_suspend(id); }
|
|
69
|
+
struct initialize {};
|
|
70
|
+
private:
|
|
71
|
+
mach_port_t id;
|
|
72
|
+
};
|
|
73
|
+
} // namespace ivm
|
|
74
|
+
|
|
75
|
+
// Windows
|
|
76
|
+
#elif _WIN32
|
|
77
|
+
#include <processthreadsapi.h>
|
|
78
|
+
namespace ivm {
|
|
79
|
+
class thread_suspend_handle {
|
|
80
|
+
public:
|
|
81
|
+
thread_suspend_handle() : id{GetCurrentThread()} {}
|
|
82
|
+
~thread_suspend_handle() = default;
|
|
83
|
+
thread_suspend_handle(const thread_suspend_handle&) = delete;
|
|
84
|
+
auto operator=(thread_suspend_handle&) = delete;
|
|
85
|
+
void suspend() const { SuspendThread(id); }
|
|
86
|
+
struct initialize {};
|
|
87
|
+
private:
|
|
88
|
+
HANDLE id;
|
|
89
|
+
};
|
|
90
|
+
} // namespace ivm
|
|
91
|
+
|
|
92
|
+
// Fallback [no-op]
|
|
93
|
+
#else
|
|
94
|
+
namespace ivm {
|
|
95
|
+
class thread_suspend_handle {
|
|
96
|
+
public:
|
|
97
|
+
thread_suspend_handle() {}
|
|
98
|
+
~thread_suspend_handle() = default;
|
|
99
|
+
thread_suspend_handle(const thread_suspend_handle&) = delete;
|
|
100
|
+
auto operator=(thread_suspend_handle&) = delete;
|
|
101
|
+
void suspend() const {}
|
|
102
|
+
struct initialize {};
|
|
103
|
+
};
|
|
104
|
+
} // namespace ivm
|
|
105
|
+
|
|
106
|
+
#endif
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#include "thread_pool.h"
|
|
2
|
+
#include <functional>
|
|
3
|
+
|
|
4
|
+
namespace ivm {
|
|
5
|
+
|
|
6
|
+
void thread_pool_t::exec(affinity_t& affinity, entry_t* entry, void* param) {
|
|
7
|
+
std::lock_guard<std::mutex> lock{mutex};
|
|
8
|
+
|
|
9
|
+
// First try to use an old thread
|
|
10
|
+
unsigned thread = std::numeric_limits<unsigned>::max();
|
|
11
|
+
if (affinity.previous < thread_data.size() && thread_data[affinity.previous].entry == nullptr) {
|
|
12
|
+
thread = affinity.previous;
|
|
13
|
+
} else {
|
|
14
|
+
for (auto ii = affinity.ids.begin(); ii != affinity.ids.end(); ) {
|
|
15
|
+
if (*ii >= thread_data.size()) {
|
|
16
|
+
ii = affinity.ids.erase(ii);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (thread_data[*ii].entry == nullptr) {
|
|
20
|
+
affinity.previous = thread = *ii;
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
++ii;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (thread == std::numeric_limits<unsigned>::max()) {
|
|
28
|
+
if (desired_size > thread_data.size()) {
|
|
29
|
+
// Thread pool hasn't yet reached `desired_size`, so we can make a new thread
|
|
30
|
+
thread = new_thread(lock);
|
|
31
|
+
affinity.previous = thread;
|
|
32
|
+
affinity.ids.insert(thread);
|
|
33
|
+
} else {
|
|
34
|
+
// Now try to re-use a non-busy thread
|
|
35
|
+
size_t offset = rr++;
|
|
36
|
+
for (size_t ii = 0; ii < thread_data.size(); ++ii) {
|
|
37
|
+
size_t jj = (rr + ii + offset) % thread_data.size();
|
|
38
|
+
if (thread_data[jj].entry == nullptr) {
|
|
39
|
+
thread = jj;
|
|
40
|
+
affinity.previous = thread;
|
|
41
|
+
affinity.ids.insert(thread);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (thread == std::numeric_limits<unsigned>::max()) {
|
|
47
|
+
// All threads are busy and pool is full, just run this in a new thread
|
|
48
|
+
std::thread tmp_thread{[=]() { entry(false, param); }};
|
|
49
|
+
tmp_thread.detach();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
thread_data[thread].entry = entry;
|
|
56
|
+
thread_data[thread].param = param;
|
|
57
|
+
thread_data[thread].cv.notify_one();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
void thread_pool_t::resize(size_t size) {
|
|
61
|
+
std::unique_lock<std::mutex> lock{mutex};
|
|
62
|
+
desired_size = size;
|
|
63
|
+
if (thread_data.size() > desired_size) {
|
|
64
|
+
for (size_t ii = desired_size; ii < thread_data.size(); ++ii) {
|
|
65
|
+
thread_data[ii].should_exit = true;
|
|
66
|
+
thread_data[ii].cv.notify_one();
|
|
67
|
+
}
|
|
68
|
+
lock.unlock();
|
|
69
|
+
for (size_t ii = desired_size; ii < thread_data.size(); ++ii) {
|
|
70
|
+
thread_data[ii].thread.join();
|
|
71
|
+
}
|
|
72
|
+
thread_data.resize(desired_size);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
auto thread_pool_t::new_thread(std::lock_guard<std::mutex>& /*lock*/) -> size_t {
|
|
77
|
+
thread_data.emplace_back();
|
|
78
|
+
auto& data = thread_data.back();
|
|
79
|
+
data.thread = std::thread{[this, &data]() {
|
|
80
|
+
std::unique_lock<std::mutex> lock{mutex};
|
|
81
|
+
while (!data.should_exit) {
|
|
82
|
+
if (data.entry == nullptr) {
|
|
83
|
+
data.cv.wait(lock);
|
|
84
|
+
} else {
|
|
85
|
+
entry_t* entry = data.entry;
|
|
86
|
+
void* param = data.param;
|
|
87
|
+
lock.unlock();
|
|
88
|
+
entry(true, param);
|
|
89
|
+
lock.lock();
|
|
90
|
+
data.entry = nullptr;
|
|
91
|
+
data.param = nullptr;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}};
|
|
95
|
+
return thread_data.size() - 1;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
} // namespace ivm
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <condition_variable>
|
|
3
|
+
#include <deque>
|
|
4
|
+
#include <limits>
|
|
5
|
+
#include <mutex>
|
|
6
|
+
#include <thread>
|
|
7
|
+
#include <unordered_set>
|
|
8
|
+
|
|
9
|
+
namespace ivm {
|
|
10
|
+
|
|
11
|
+
class thread_pool_t {
|
|
12
|
+
public:
|
|
13
|
+
using entry_t = void(bool, void*);
|
|
14
|
+
class affinity_t {
|
|
15
|
+
friend thread_pool_t;
|
|
16
|
+
std::unordered_set<unsigned> ids;
|
|
17
|
+
unsigned previous = std::numeric_limits<unsigned>::max();
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
explicit thread_pool_t(size_t desired_size) noexcept : desired_size{desired_size} {}
|
|
21
|
+
thread_pool_t(const thread_pool_t&) = delete;
|
|
22
|
+
~thread_pool_t() { resize(0); }
|
|
23
|
+
auto operator= (const thread_pool_t&) = delete;
|
|
24
|
+
|
|
25
|
+
void exec(affinity_t& affinity, entry_t* entry, void* param);
|
|
26
|
+
void resize(size_t size);
|
|
27
|
+
|
|
28
|
+
private:
|
|
29
|
+
auto new_thread(std::lock_guard<std::mutex>& /*lock*/) -> size_t;
|
|
30
|
+
|
|
31
|
+
struct thread_data_t {
|
|
32
|
+
std::thread thread;
|
|
33
|
+
std::condition_variable cv;
|
|
34
|
+
entry_t* entry = nullptr;
|
|
35
|
+
void* param = nullptr;
|
|
36
|
+
bool should_exit = false;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
size_t desired_size;
|
|
40
|
+
size_t rr = 0;
|
|
41
|
+
std::mutex mutex;
|
|
42
|
+
std::deque<thread_data_t> thread_data;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
} // namespace ivm
|