@@ -3699,8 +3699,8 @@ inline AsyncWorker::AsyncWorker(const Object& receiver,
3699
3699
_env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
3700
3700
NAPI_THROW_IF_FAILED_VOID (_env, status);
3701
3701
3702
- status = napi_create_async_work (_env, resource, resource_id, OnExecute ,
3703
- OnWorkComplete , this , &_work);
3702
+ status = napi_create_async_work (_env, resource, resource_id, OnAsyncWorkExecute ,
3703
+ OnAsyncWorkComplete , this , &_work);
3704
3704
NAPI_THROW_IF_FAILED_VOID (_env, status);
3705
3705
}
3706
3706
@@ -3725,8 +3725,8 @@ inline AsyncWorker::AsyncWorker(Napi::Env env,
3725
3725
_env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
3726
3726
NAPI_THROW_IF_FAILED_VOID (_env, status);
3727
3727
3728
- status = napi_create_async_work (_env, resource, resource_id, OnExecute ,
3729
- OnWorkComplete , this , &_work);
3728
+ status = napi_create_async_work (_env, resource, resource_id, OnAsyncWorkExecute ,
3729
+ OnAsyncWorkComplete , this , &_work);
3730
3730
NAPI_THROW_IF_FAILED_VOID (_env, status);
3731
3731
}
3732
3732
@@ -3813,40 +3813,51 @@ inline void AsyncWorker::SetError(const std::string& error) {
3813
3813
inline std::vector<napi_value> AsyncWorker::GetResult (Napi::Env /* env*/ ) {
3814
3814
return {};
3815
3815
}
3816
+ // The OnAsyncWorkExecute method receives an napi_env argument. However, do NOT
3817
+ // use it within this method, as it does not run on the main thread and must
3818
+ // not run any method that would cause JavaScript to run. In practice, this
3819
+ // means that almost any use of napi_env will be incorrect.
3820
+ inline void OnAsyncWorkExecute (napi_env env, void * asyncworker) {
3821
+ AsyncWorker* self = static_cast <AsyncWorker*>(asyncworker);
3822
+ self->OnExecute (env);
3823
+ }
3816
3824
// The OnExecute method receives an napi_env argument. However, do NOT
3817
3825
// use it within this method, as it does not run on the main thread and must
3818
3826
// not run any method that would cause JavaScript to run. In practice, this
3819
3827
// means that almost any use of napi_env will be incorrect.
3820
- inline void AsyncWorker::OnExecute (napi_env /* DO_NOT_USE*/ , void * this_pointer) {
3821
- AsyncWorker* self = static_cast <AsyncWorker*>(this_pointer);
3828
+ inline void AsyncWorker::OnExecute (napi_env /* DO_NOT_USE*/ ) {
3822
3829
#ifdef NAPI_CPP_EXCEPTIONS
3823
3830
try {
3824
- self ->Execute ();
3831
+ this ->Execute ();
3825
3832
} catch (const std::exception& e) {
3826
- self ->SetError (e.what ());
3833
+ this ->SetError (e.what ());
3827
3834
}
3828
3835
#else // NAPI_CPP_EXCEPTIONS
3829
- self ->Execute ();
3836
+ this ->Execute ();
3830
3837
#endif // NAPI_CPP_EXCEPTIONS
3831
3838
}
3832
3839
3833
- inline void AsyncWorker::OnWorkComplete (
3834
- napi_env /* env*/ , napi_status status, void * this_pointer) {
3835
- AsyncWorker* self = static_cast <AsyncWorker*>(this_pointer);
3840
+ inline void OnAsyncWorkComplete (napi_env env,
3841
+ napi_status status,
3842
+ void * asyncworker) {
3843
+ AsyncWorker* self = static_cast <AsyncWorker*>(asyncworker);
3844
+ self->OnWorkComplete (env, status);
3845
+ }
3846
+ inline void AsyncWorker::OnWorkComplete (napi_env /* env*/ , napi_status status) {
3836
3847
if (status != napi_cancelled) {
3837
- HandleScope scope (self ->_env );
3848
+ HandleScope scope (this ->_env );
3838
3849
details::WrapCallback ([&] {
3839
- if (self ->_error .size () == 0 ) {
3840
- self ->OnOK ();
3850
+ if (this ->_error .size () == 0 ) {
3851
+ this ->OnOK ();
3841
3852
}
3842
3853
else {
3843
- self ->OnError (Error::New (self ->_env , self ->_error ));
3854
+ this ->OnError (Error::New (this ->_env , this ->_error ));
3844
3855
}
3845
3856
return nullptr ;
3846
3857
});
3847
3858
}
3848
- if (!self ->_suppress_destruct ) {
3849
- self ->Destroy ();
3859
+ if (!this ->_suppress_destruct ) {
3860
+ this ->Destroy ();
3850
3861
}
3851
3862
}
3852
3863
@@ -4172,9 +4183,38 @@ inline void ThreadSafeFunction::CallJS(napi_env env,
4172
4183
}
4173
4184
4174
4185
// //////////////////////////////////////////////////////////////////////////////
4175
- // Async Progress Worker class
4186
+ // Async Progress Worker Base class
4176
4187
// //////////////////////////////////////////////////////////////////////////////
4188
+ inline AsyncProgressWorkerBase::AsyncProgressWorkerBase (const Object& receiver,
4189
+ const Function& callback,
4190
+ const char * resource_name,
4191
+ const Object& resource)
4192
+ : AsyncWorker(receiver, callback, resource_name, resource) {
4193
+ _tsfn = ThreadSafeFunction::New (callback.Env (), callback, resource_name, 1 , 1 );
4194
+ }
4177
4195
4196
+ #if NAPI_VERSION > 4
4197
+ inline AsyncProgressWorkerBase::AsyncProgressWorkerBase (Napi::Env env,
4198
+ const char * resource_name,
4199
+ const Object& resource)
4200
+ : AsyncWorker(env, resource_name, resource) {
4201
+ // TODO: Once the changes to make the callback optional for threadsafe
4202
+ // functions are no longer optional we can remove the dummy Function here.
4203
+ Function callback;
4204
+ _tsfn = ThreadSafeFunction::New (env, callback, resource_name, 1 , 1 );
4205
+ }
4206
+ #endif
4207
+
4208
+ inline void OnAsyncWorkProgress (Napi::Env /* env */ ,
4209
+ Napi::Function /* jsCallback */ ,
4210
+ void * asyncworker) {
4211
+ AsyncProgressWorkerBase* asyncprogressworker = static_cast <AsyncProgressWorkerBase*>(asyncworker);
4212
+ asyncprogressworker->OnWorkProgress ();
4213
+ }
4214
+
4215
+ // //////////////////////////////////////////////////////////////////////////////
4216
+ // Async Progress Worker class
4217
+ // //////////////////////////////////////////////////////////////////////////////
4178
4218
template <class T >
4179
4219
inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback)
4180
4220
: AsyncProgressWorker(callback, " generic" ) {
@@ -4217,10 +4257,9 @@ inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
4217
4257
const Function& callback,
4218
4258
const char * resource_name,
4219
4259
const Object& resource)
4220
- : AsyncWorker (receiver, callback, resource_name, resource),
4260
+ : AsyncProgressWorkerBase (receiver, callback, resource_name, resource),
4221
4261
_asyncdata (nullptr ),
4222
4262
_asyncsize(0 ) {
4223
- _tsfn = ThreadSafeFunction::New (callback.Env (), callback, resource_name, 1 , 1 );
4224
4263
}
4225
4264
4226
4265
#if NAPI_VERSION > 4
@@ -4239,27 +4278,23 @@ template<class T>
4239
4278
inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
4240
4279
const char * resource_name,
4241
4280
const Object& resource)
4242
- : AsyncWorker (env, resource_name, resource),
4281
+ : AsyncProgressWorkerBase (env, resource_name, resource),
4243
4282
_asyncdata (nullptr ),
4244
4283
_asyncsize(0 ) {
4245
- // TODO: Once the changes to make the callback optional for threadsafe
4246
- // functions are no longer optional we can remove the dummy Function here.
4247
- Function callback;
4248
- _tsfn = ThreadSafeFunction::New (env, callback, resource_name, 1 , 1 );
4249
4284
}
4250
4285
#endif
4251
4286
4252
4287
template <class T >
4253
4288
inline AsyncProgressWorker<T>::~AsyncProgressWorker () {
4254
4289
// Abort pending tsfn call.
4255
4290
// Don't send progress events after we've already completed.
4256
- _tsfn.Abort ();
4291
+ this -> _tsfn .Abort ();
4257
4292
{
4258
- std::lock_guard<std::mutex> lock (_mutex);
4293
+ std::lock_guard<std::mutex> lock (this -> _mutex );
4259
4294
_asyncdata = nullptr ;
4260
4295
_asyncsize = 0 ;
4261
4296
}
4262
- _tsfn.Release ();
4297
+ this -> _tsfn .Release ();
4263
4298
}
4264
4299
4265
4300
template <class T >
@@ -4269,20 +4304,18 @@ inline void AsyncProgressWorker<T>::Execute() {
4269
4304
}
4270
4305
4271
4306
template <class T >
4272
- inline void AsyncProgressWorker<T>::WorkProgress_(Napi::Env /* env */ , Napi::Function /* jsCallback */ , void * _data) {
4273
- AsyncProgressWorker* self = static_cast <AsyncProgressWorker*>(_data);
4274
-
4307
+ inline void AsyncProgressWorker<T>::OnWorkProgress() {
4275
4308
T* data;
4276
4309
size_t size;
4277
4310
{
4278
- std::lock_guard<std::mutex> lock (self ->_mutex );
4279
- data = self ->_asyncdata ;
4280
- size = self ->_asyncsize ;
4281
- self ->_asyncdata = nullptr ;
4282
- self ->_asyncsize = 0 ;
4311
+ std::lock_guard<std::mutex> lock (this ->_mutex );
4312
+ data = this ->_asyncdata ;
4313
+ size = this ->_asyncsize ;
4314
+ this ->_asyncdata = nullptr ;
4315
+ this ->_asyncsize = 0 ;
4283
4316
}
4284
4317
4285
- self ->OnProgress (data, size);
4318
+ this ->OnProgress (data, size);
4286
4319
delete[] data;
4287
4320
}
4288
4321
@@ -4293,19 +4326,19 @@ inline void AsyncProgressWorker<T>::SendProgress_(const T* data, size_t count) {
4293
4326
4294
4327
T* old_data;
4295
4328
{
4296
- std::lock_guard<std::mutex> lock (_mutex);
4329
+ std::lock_guard<std::mutex> lock (this -> _mutex );
4297
4330
old_data = _asyncdata;
4298
4331
_asyncdata = new_data;
4299
4332
_asyncsize = count;
4300
4333
}
4301
- _tsfn.NonBlockingCall (this , WorkProgress_ );
4334
+ this -> _tsfn .NonBlockingCall (this , OnAsyncWorkProgress );
4302
4335
4303
4336
delete[] old_data;
4304
4337
}
4305
4338
4306
4339
template <class T >
4307
4340
inline void AsyncProgressWorker<T>::Signal() const {
4308
- _tsfn.NonBlockingCall (this , WorkProgress_ );
4341
+ this -> _tsfn .NonBlockingCall (this , OnAsyncWorkProgress );
4309
4342
}
4310
4343
4311
4344
template <class T >
@@ -4318,6 +4351,151 @@ inline void AsyncProgressWorker<T>::ExecutionProgress::Send(const T* data, size_
4318
4351
_worker->SendProgress_ (data, count);
4319
4352
}
4320
4353
4354
+ // //////////////////////////////////////////////////////////////////////////////
4355
+ // Async Progress Queue Worker class
4356
+ // //////////////////////////////////////////////////////////////////////////////
4357
+ template <class T >
4358
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Function& callback)
4359
+ : AsyncProgressQueueWorker(callback, " generic" ) {
4360
+ }
4361
+
4362
+ template <class T >
4363
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Function& callback,
4364
+ const char * resource_name)
4365
+ : AsyncProgressQueueWorker(callback, resource_name, Object::New(callback.Env())) {
4366
+ }
4367
+
4368
+ template <class T >
4369
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Function& callback,
4370
+ const char * resource_name,
4371
+ const Object& resource)
4372
+ : AsyncProgressQueueWorker(Object::New(callback.Env()),
4373
+ callback,
4374
+ resource_name,
4375
+ resource) {
4376
+ }
4377
+
4378
+ template <class T >
4379
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Object& receiver,
4380
+ const Function& callback)
4381
+ : AsyncProgressQueueWorker(receiver, callback, " generic" ) {
4382
+ }
4383
+
4384
+ template <class T >
4385
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Object& receiver,
4386
+ const Function& callback,
4387
+ const char * resource_name)
4388
+ : AsyncProgressQueueWorker(receiver,
4389
+ callback,
4390
+ resource_name,
4391
+ Object::New (callback.Env())) {
4392
+ }
4393
+
4394
+ template <class T >
4395
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(const Object& receiver,
4396
+ const Function& callback,
4397
+ const char * resource_name,
4398
+ const Object& resource)
4399
+ : AsyncProgressWorkerBase(receiver, callback, resource_name, resource) {
4400
+ }
4401
+
4402
+ #if NAPI_VERSION > 4
4403
+ template <class T >
4404
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(Napi::Env env)
4405
+ : AsyncProgressQueueWorker(env, " generic" ) {
4406
+ }
4407
+
4408
+ template <class T >
4409
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(Napi::Env env,
4410
+ const char * resource_name)
4411
+ : AsyncProgressQueueWorker(env, resource_name, Object::New(env)) {
4412
+ }
4413
+
4414
+ template <class T >
4415
+ inline AsyncProgressQueueWorker<T>::AsyncProgressQueueWorker(Napi::Env env,
4416
+ const char * resource_name,
4417
+ const Object& resource)
4418
+ : AsyncProgressWorkerBase(env, resource_name, resource) {
4419
+ }
4420
+ #endif
4421
+
4422
+ template <class T >
4423
+ inline AsyncProgressQueueWorker<T>::~AsyncProgressQueueWorker () {
4424
+ // Abort pending tsfn call.
4425
+ // Don't send progress events after we've already completed.
4426
+ this ->_tsfn .Abort ();
4427
+ {
4428
+ std::lock_guard<std::mutex> lock (this ->_mutex );
4429
+ while (!_asyncdata.empty ()) {
4430
+ std::pair<T*, size_t > &datapair = _asyncdata.front ();
4431
+ T *data = datapair.first ;
4432
+
4433
+ _asyncdata.pop ();
4434
+
4435
+ delete[] data;
4436
+ }
4437
+ }
4438
+ this ->_tsfn .Release ();
4439
+ }
4440
+
4441
+ template <class T >
4442
+ inline void AsyncProgressQueueWorker<T>::Execute() {
4443
+ ExecutionProgress progress (this );
4444
+ Execute (progress);
4445
+ }
4446
+
4447
+ template <class T >
4448
+ inline void AsyncProgressQueueWorker<T>::OnWorkProgress() {
4449
+ this ->_mutex .lock ();
4450
+ while (!this ->_asyncdata .empty ()) {
4451
+ std::pair<T*, size_t > &datapair = this ->_asyncdata .front ();
4452
+
4453
+ T *data = datapair.first ;
4454
+ size_t size = datapair.second ;
4455
+
4456
+ this ->_asyncdata .pop ();
4457
+ this ->_mutex .unlock ();
4458
+
4459
+ this ->OnProgress (data, size);
4460
+ delete[] data;
4461
+
4462
+ this ->_mutex .lock ();
4463
+ }
4464
+ this ->_mutex .unlock ();
4465
+ }
4466
+
4467
+ template <class T >
4468
+ inline void AsyncProgressQueueWorker<T>::SendProgress_(const T* data, size_t count) {
4469
+ T* new_data = new T[count];
4470
+ std::copy (data, data + count, new_data);
4471
+
4472
+ {
4473
+ std::lock_guard<std::mutex> lock (this ->_mutex );
4474
+ _asyncdata.push (std::pair<T*, size_t >(new_data, count));
4475
+ }
4476
+ this ->_tsfn .NonBlockingCall (this , OnAsyncWorkProgress);
4477
+ }
4478
+
4479
+ template <class T >
4480
+ inline void AsyncProgressQueueWorker<T>::Signal() const {
4481
+ this ->_tsfn .NonBlockingCall (this , OnAsyncWorkProgress);
4482
+ }
4483
+
4484
+ template <class T >
4485
+ inline void AsyncProgressQueueWorker<T>::OnWorkComplete(napi_env env, napi_status status) {
4486
+ this ->OnWorkProgress ();
4487
+ AsyncWorker::OnWorkComplete (env, status);
4488
+ }
4489
+
4490
+ template <class T >
4491
+ inline void AsyncProgressQueueWorker<T>::ExecutionProgress::Signal() const {
4492
+ _worker->Signal ();
4493
+ }
4494
+
4495
+ template <class T >
4496
+ inline void AsyncProgressQueueWorker<T>::ExecutionProgress::Send(const T* data, size_t count) const {
4497
+ _worker->SendProgress_ (data, count);
4498
+ }
4321
4499
#endif
4322
4500
4323
4501
// //////////////////////////////////////////////////////////////////////////////
0 commit comments