|
9 | 9 |
|
10 | 10 | // Note: Do not include this file directly! Include "napi.h" instead.
|
11 | 11 |
|
| 12 | +#include <algorithm> |
12 | 13 | #include <cstring>
|
| 14 | +#include <mutex> |
13 | 15 | #include <type_traits>
|
14 | 16 |
|
15 | 17 | namespace Napi {
|
@@ -4112,6 +4114,91 @@ inline void ThreadSafeFunction::CallJS(napi_env env,
|
4112 | 4114 | Function(env, jsCallback).Call({});
|
4113 | 4115 | }
|
4114 | 4116 | }
|
| 4117 | + |
| 4118 | +//////////////////////////////////////////////////////////////////////////////// |
| 4119 | +// Async Progress Worker class |
| 4120 | +//////////////////////////////////////////////////////////////////////////////// |
| 4121 | + |
| 4122 | +template<class T> |
| 4123 | +inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback, |
| 4124 | + const char* resource_name, |
| 4125 | + const Object& resource) |
| 4126 | + : AsyncWorker(callback, resource_name, resource), _asyncdata(nullptr), _asyncsize(0) { |
| 4127 | + _tsfn = ThreadSafeFunction::New(callback.Env(), callback, resource_name, 1, 1); |
| 4128 | +} |
| 4129 | + |
| 4130 | +template<class T> |
| 4131 | +inline AsyncProgressWorker<T>::~AsyncProgressWorker() { |
| 4132 | + // Abort pending tsfn call. |
| 4133 | + // Don't send progress events after we've already completed. |
| 4134 | + _tsfn.Abort(); |
| 4135 | + { |
| 4136 | + std::lock_guard<std::mutex> lock(_mutex); |
| 4137 | + _asyncdata = nullptr; |
| 4138 | + _asyncsize = 0; |
| 4139 | + } |
| 4140 | + _tsfn.Release(); |
| 4141 | +} |
| 4142 | + |
| 4143 | +template<class T> |
| 4144 | +inline void AsyncProgressWorker<T>::Execute() { |
| 4145 | + ExecutionProgress progress(this); |
| 4146 | + Execute(progress); |
| 4147 | +} |
| 4148 | + |
| 4149 | +template<class T> |
| 4150 | +inline void AsyncProgressWorker<T>::WorkProgress_(Napi::Env /* env */, Napi::Function /* jsCallback */, void* _data) { |
| 4151 | + AsyncProgressWorker* self = static_cast<AsyncProgressWorker*>(_data); |
| 4152 | + |
| 4153 | + T* data; |
| 4154 | + size_t size; |
| 4155 | + { |
| 4156 | + std::lock_guard<std::mutex> lock(self->_mutex); |
| 4157 | + data = self->_asyncdata; |
| 4158 | + size = self->_asyncsize; |
| 4159 | + self->_asyncdata = nullptr; |
| 4160 | + self->_asyncsize = 0; |
| 4161 | + } |
| 4162 | + |
| 4163 | + self->OnProgress(data, size); |
| 4164 | + delete[] data; |
| 4165 | +} |
| 4166 | + |
| 4167 | +template<class T> |
| 4168 | +inline void AsyncProgressWorker<T>::SendProgress_(const T* data, size_t count) { |
| 4169 | + T* new_data = new T[count]; |
| 4170 | + { |
| 4171 | + T* it = new_data; |
| 4172 | + std::copy(data, data + count, it); |
| 4173 | + } |
| 4174 | + |
| 4175 | + T* old_data; |
| 4176 | + { |
| 4177 | + std::lock_guard<std::mutex> lock(_mutex); |
| 4178 | + old_data = _asyncdata; |
| 4179 | + _asyncdata = new_data; |
| 4180 | + _asyncsize = count; |
| 4181 | + } |
| 4182 | + _tsfn.NonBlockingCall(this, WorkProgress_); |
| 4183 | + |
| 4184 | + delete[] old_data; |
| 4185 | +} |
| 4186 | + |
| 4187 | +template<class T> |
| 4188 | +inline void AsyncProgressWorker<T>::Signal() const { |
| 4189 | + _tsfn.NonBlockingCall(this, WorkProgress_); |
| 4190 | +} |
| 4191 | + |
| 4192 | +template<class T> |
| 4193 | +inline void AsyncProgressWorker<T>::ExecutionProgress::Signal() const { |
| 4194 | + _that->Signal(); |
| 4195 | +} |
| 4196 | + |
| 4197 | +template<class T> |
| 4198 | +inline void AsyncProgressWorker<T>::ExecutionProgress::Send(const T* data, size_t count) const { |
| 4199 | + _that->SendProgress_(data, count); |
| 4200 | +} |
| 4201 | + |
4115 | 4202 | #endif
|
4116 | 4203 |
|
4117 | 4204 | ////////////////////////////////////////////////////////////////////////////////
|
|
0 commit comments