Skip to content

Commit c072057

Browse files
committed
src: unify thread pool work
Instead of using the libuv mechanism directly, provide an internal `ThreadPoolWork` wrapper that takes care of increasing/decreasing the waiting request counter. PR-URL: #19377 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 2b31504 commit c072057

File tree

4 files changed

+108
-128
lines changed

4 files changed

+108
-128
lines changed

src/node_api.cc

+28-45
Original file line numberDiff line numberDiff line change
@@ -3338,7 +3338,7 @@ static napi_status ConvertUVErrorCode(int code) {
33383338
}
33393339

33403340
// Wrapper around uv_work_t which calls user-provided callbacks.
3341-
class Work : public node::AsyncResource {
3341+
class Work : public node::AsyncResource, public node::ThreadPoolWork {
33423342
private:
33433343
explicit Work(napi_env env,
33443344
v8::Local<v8::Object> async_resource,
@@ -3349,15 +3349,14 @@ class Work : public node::AsyncResource {
33493349
: AsyncResource(env->isolate,
33503350
async_resource,
33513351
*v8::String::Utf8Value(env->isolate, async_resource_name)),
3352-
_env(env),
3353-
_data(data),
3354-
_execute(execute),
3355-
_complete(complete) {
3356-
memset(&_request, 0, sizeof(_request));
3357-
_request.data = this;
3352+
ThreadPoolWork(node::Environment::GetCurrent(env->isolate)),
3353+
_env(env),
3354+
_data(data),
3355+
_execute(execute),
3356+
_complete(complete) {
33583357
}
33593358

3360-
~Work() { }
3359+
virtual ~Work() { }
33613360

33623361
public:
33633362
static Work* New(napi_env env,
@@ -3374,47 +3373,36 @@ class Work : public node::AsyncResource {
33743373
delete work;
33753374
}
33763375

3377-
static void ExecuteCallback(uv_work_t* req) {
3378-
Work* work = static_cast<Work*>(req->data);
3379-
work->_execute(work->_env, work->_data);
3376+
void DoThreadPoolWork() override {
3377+
_execute(_env, _data);
33803378
}
33813379

3382-
static void CompleteCallback(uv_work_t* req, int status) {
3383-
Work* work = static_cast<Work*>(req->data);
3380+
void AfterThreadPoolWork(int status) {
3381+
if (_complete == nullptr)
3382+
return;
33843383

3385-
if (work->_complete != nullptr) {
3386-
napi_env env = work->_env;
3384+
// Establish a handle scope here so that every callback doesn't have to.
3385+
// Also it is needed for the exception-handling below.
3386+
v8::HandleScope scope(_env->isolate);
33873387

3388-
// Establish a handle scope here so that every callback doesn't have to.
3389-
// Also it is needed for the exception-handling below.
3390-
v8::HandleScope scope(env->isolate);
3391-
node::Environment* env_ = node::Environment::GetCurrent(env->isolate);
3392-
env_->DecreaseWaitingRequestCounter();
3388+
CallbackScope callback_scope(this);
33933389

3394-
CallbackScope callback_scope(work);
3390+
NAPI_CALL_INTO_MODULE(_env,
3391+
_complete(_env, ConvertUVErrorCode(status), _data),
3392+
[this] (v8::Local<v8::Value> local_err) {
3393+
// If there was an unhandled exception in the complete callback,
3394+
// report it as a fatal exception. (There is no JavaScript on the
3395+
// callstack that can possibly handle it.)
3396+
v8impl::trigger_fatal_exception(_env, local_err);
3397+
});
33953398

3396-
NAPI_CALL_INTO_MODULE(env,
3397-
work->_complete(env, ConvertUVErrorCode(status), work->_data),
3398-
[env] (v8::Local<v8::Value> local_err) {
3399-
// If there was an unhandled exception in the complete callback,
3400-
// report it as a fatal exception. (There is no JavaScript on the
3401-
// callstack that can possibly handle it.)
3402-
v8impl::trigger_fatal_exception(env, local_err);
3403-
});
3404-
3405-
// Note: Don't access `work` after this point because it was
3406-
// likely deleted by the complete callback.
3407-
}
3408-
}
3409-
3410-
uv_work_t* Request() {
3411-
return &_request;
3399+
// Note: Don't access `work` after this point because it was
3400+
// likely deleted by the complete callback.
34123401
}
34133402

34143403
private:
34153404
napi_env _env;
34163405
void* _data;
3417-
uv_work_t _request;
34183406
napi_async_execute_callback _execute;
34193407
napi_async_complete_callback _complete;
34203408
};
@@ -3491,12 +3479,7 @@ napi_status napi_queue_async_work(napi_env env, napi_async_work work) {
34913479

34923480
uvimpl::Work* w = reinterpret_cast<uvimpl::Work*>(work);
34933481

3494-
node::Environment* env_ = node::Environment::GetCurrent(env->isolate);
3495-
env_->IncreaseWaitingRequestCounter();
3496-
CALL_UV(env, uv_queue_work(event_loop,
3497-
w->Request(),
3498-
uvimpl::Work::ExecuteCallback,
3499-
uvimpl::Work::CompleteCallback));
3482+
w->ScheduleWork();
35003483

35013484
return napi_clear_last_error(env);
35023485
}
@@ -3507,7 +3490,7 @@ napi_status napi_cancel_async_work(napi_env env, napi_async_work work) {
35073490

35083491
uvimpl::Work* w = reinterpret_cast<uvimpl::Work*>(work);
35093492

3510-
CALL_UV(env, uv_cancel(reinterpret_cast<uv_req_t*>(w->Request())));
3493+
CALL_UV(env, w->CancelWork());
35113494

35123495
return napi_clear_last_error(env);
35133496
}

src/node_crypto.cc

+30-69
Original file line numberDiff line numberDiff line change
@@ -4556,7 +4556,7 @@ bool ECDH::IsKeyPairValid() {
45564556
}
45574557

45584558

4559-
class PBKDF2Request : public AsyncWrap {
4559+
class PBKDF2Request : public AsyncWrap, public ThreadPoolWork {
45604560
public:
45614561
PBKDF2Request(Environment* env,
45624562
Local<Object> object,
@@ -4566,6 +4566,7 @@ class PBKDF2Request : public AsyncWrap {
45664566
int keylen,
45674567
int iteration_count)
45684568
: AsyncWrap(env, object, AsyncWrap::PROVIDER_PBKDF2REQUEST),
4569+
ThreadPoolWork(env),
45694570
digest_(digest),
45704571
success_(false),
45714572
pass_(std::move(pass)),
@@ -4574,21 +4575,14 @@ class PBKDF2Request : public AsyncWrap {
45744575
iteration_count_(iteration_count) {
45754576
}
45764577

4577-
uv_work_t* work_req() {
4578-
return &work_req_;
4579-
}
4580-
45814578
size_t self_size() const override { return sizeof(*this); }
45824579

4583-
static void Work(uv_work_t* work_req);
4584-
void Work();
4580+
void DoThreadPoolWork() override;
4581+
void AfterThreadPoolWork(int status) override;
45854582

4586-
static void After(uv_work_t* work_req, int status);
45874583
void After(Local<Value> (*argv)[2]);
4588-
void After();
45894584

45904585
private:
4591-
uv_work_t work_req_;
45924586
const EVP_MD* digest_;
45934587
bool success_;
45944588
MallocedBuffer<char> pass_;
@@ -4598,7 +4592,7 @@ class PBKDF2Request : public AsyncWrap {
45984592
};
45994593

46004594

4601-
void PBKDF2Request::Work() {
4595+
void PBKDF2Request::DoThreadPoolWork() {
46024596
success_ =
46034597
PKCS5_PBKDF2_HMAC(
46044598
pass_.data, pass_.size,
@@ -4611,12 +4605,6 @@ void PBKDF2Request::Work() {
46114605
}
46124606

46134607

4614-
void PBKDF2Request::Work(uv_work_t* work_req) {
4615-
PBKDF2Request* req = ContainerOf(&PBKDF2Request::work_req_, work_req);
4616-
req->Work();
4617-
}
4618-
4619-
46204608
void PBKDF2Request::After(Local<Value> (*argv)[2]) {
46214609
if (success_) {
46224610
(*argv)[0] = Null(env()->isolate());
@@ -4629,7 +4617,12 @@ void PBKDF2Request::After(Local<Value> (*argv)[2]) {
46294617
}
46304618

46314619

4632-
void PBKDF2Request::After() {
4620+
void PBKDF2Request::AfterThreadPoolWork(int status) {
4621+
std::unique_ptr<PBKDF2Request> req(this);
4622+
if (status == UV_ECANCELED)
4623+
return;
4624+
CHECK_EQ(status, 0);
4625+
46334626
HandleScope handle_scope(env()->isolate());
46344627
Context::Scope context_scope(env()->context());
46354628
Local<Value> argv[2];
@@ -4638,17 +4631,6 @@ void PBKDF2Request::After() {
46384631
}
46394632

46404633

4641-
void PBKDF2Request::After(uv_work_t* work_req, int status) {
4642-
std::unique_ptr<PBKDF2Request> req(
4643-
ContainerOf(&PBKDF2Request::work_req_, work_req));
4644-
req->env()->DecreaseWaitingRequestCounter();
4645-
if (status == UV_ECANCELED)
4646-
return;
4647-
CHECK_EQ(status, 0);
4648-
req->After();
4649-
}
4650-
4651-
46524634
void PBKDF2(const FunctionCallbackInfo<Value>& args) {
46534635
Environment* env = Environment::GetCurrent(args);
46544636

@@ -4695,14 +4677,10 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
46954677
if (args[5]->IsFunction()) {
46964678
obj->Set(env->context(), env->ondone_string(), args[5]).FromJust();
46974679

4698-
env->IncreaseWaitingRequestCounter();
4699-
uv_queue_work(env->event_loop(),
4700-
req.release()->work_req(),
4701-
PBKDF2Request::Work,
4702-
PBKDF2Request::After);
4680+
req.release()->ScheduleWork();
47034681
} else {
47044682
env->PrintSyncTrace();
4705-
req->Work();
4683+
req->DoThreadPoolWork();
47064684
Local<Value> argv[2];
47074685
req->After(&argv);
47084686

@@ -4715,7 +4693,7 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
47154693

47164694

47174695
// Only instantiate within a valid HandleScope.
4718-
class RandomBytesRequest : public AsyncWrap {
4696+
class RandomBytesRequest : public AsyncWrap, public ThreadPoolWork {
47194697
public:
47204698
enum FreeMode { FREE_DATA, DONT_FREE_DATA };
47214699

@@ -4725,16 +4703,13 @@ class RandomBytesRequest : public AsyncWrap {
47254703
char* data,
47264704
FreeMode free_mode)
47274705
: AsyncWrap(env, object, AsyncWrap::PROVIDER_RANDOMBYTESREQUEST),
4706+
ThreadPoolWork(env),
47284707
error_(0),
47294708
size_(size),
47304709
data_(data),
47314710
free_mode_(free_mode) {
47324711
}
47334712

4734-
uv_work_t* work_req() {
4735-
return &work_req_;
4736-
}
4737-
47384713
inline size_t size() const {
47394714
return size_;
47404715
}
@@ -4772,7 +4747,8 @@ class RandomBytesRequest : public AsyncWrap {
47724747

47734748
size_t self_size() const override { return sizeof(*this); }
47744749

4775-
uv_work_t work_req_;
4750+
void DoThreadPoolWork() override;
4751+
void AfterThreadPoolWork(int status) override;
47764752

47774753
private:
47784754
unsigned long error_; // NOLINT(runtime/int)
@@ -4782,21 +4758,17 @@ class RandomBytesRequest : public AsyncWrap {
47824758
};
47834759

47844760

4785-
void RandomBytesWork(uv_work_t* work_req) {
4786-
RandomBytesRequest* req =
4787-
ContainerOf(&RandomBytesRequest::work_req_, work_req);
4788-
4761+
void RandomBytesRequest::DoThreadPoolWork() {
47894762
// Ensure that OpenSSL's PRNG is properly seeded.
47904763
CheckEntropy();
47914764

4792-
const int r = RAND_bytes(reinterpret_cast<unsigned char*>(req->data()),
4793-
req->size());
4765+
const int r = RAND_bytes(reinterpret_cast<unsigned char*>(data_), size_);
47944766

47954767
// RAND_bytes() returns 0 on error.
47964768
if (r == 0) {
4797-
req->set_error(ERR_get_error()); // NOLINT(runtime/int)
4769+
set_error(ERR_get_error()); // NOLINT(runtime/int)
47984770
} else if (r == -1) {
4799-
req->set_error(static_cast<unsigned long>(-1)); // NOLINT(runtime/int)
4771+
set_error(static_cast<unsigned long>(-1)); // NOLINT(runtime/int)
48004772
}
48014773
}
48024774

@@ -4834,27 +4806,24 @@ void RandomBytesCheck(RandomBytesRequest* req, Local<Value> (*argv)[2]) {
48344806
}
48354807

48364808

4837-
void RandomBytesAfter(uv_work_t* work_req, int status) {
4838-
std::unique_ptr<RandomBytesRequest> req(
4839-
ContainerOf(&RandomBytesRequest::work_req_, work_req));
4840-
Environment* env = req->env();
4841-
env->DecreaseWaitingRequestCounter();
4809+
void RandomBytesRequest::AfterThreadPoolWork(int status) {
4810+
std::unique_ptr<RandomBytesRequest> req(this);
48424811
if (status == UV_ECANCELED)
48434812
return;
48444813
CHECK_EQ(status, 0);
4845-
HandleScope handle_scope(env->isolate());
4846-
Context::Scope context_scope(env->context());
4814+
HandleScope handle_scope(env()->isolate());
4815+
Context::Scope context_scope(env()->context());
48474816
Local<Value> argv[2];
4848-
RandomBytesCheck(req.get(), &argv);
4849-
req->MakeCallback(env->ondone_string(), arraysize(argv), argv);
4817+
RandomBytesCheck(this, &argv);
4818+
MakeCallback(env()->ondone_string(), arraysize(argv), argv);
48504819
}
48514820

48524821

48534822
void RandomBytesProcessSync(Environment* env,
48544823
std::unique_ptr<RandomBytesRequest> req,
48554824
Local<Value> (*argv)[2]) {
48564825
env->PrintSyncTrace();
4857-
RandomBytesWork(req->work_req());
4826+
req->DoThreadPoolWork();
48584827
RandomBytesCheck(req.get(), argv);
48594828

48604829
if (!(*argv)[0]->IsNull())
@@ -4881,11 +4850,7 @@ void RandomBytes(const FunctionCallbackInfo<Value>& args) {
48814850
if (args[1]->IsFunction()) {
48824851
obj->Set(env->context(), env->ondone_string(), args[1]).FromJust();
48834852

4884-
env->IncreaseWaitingRequestCounter();
4885-
uv_queue_work(env->event_loop(),
4886-
req.release()->work_req(),
4887-
RandomBytesWork,
4888-
RandomBytesAfter);
4853+
req.release()->ScheduleWork();
48894854
args.GetReturnValue().Set(obj);
48904855
} else {
48914856
Local<Value> argv[2];
@@ -4921,11 +4886,7 @@ void RandomBytesBuffer(const FunctionCallbackInfo<Value>& args) {
49214886
if (args[3]->IsFunction()) {
49224887
obj->Set(env->context(), env->ondone_string(), args[3]).FromJust();
49234888

4924-
env->IncreaseWaitingRequestCounter();
4925-
uv_queue_work(env->event_loop(),
4926-
req.release()->work_req(),
4927-
RandomBytesWork,
4928-
RandomBytesAfter);
4889+
req.release()->ScheduleWork();
49294890
args.GetReturnValue().Set(obj);
49304891
} else {
49314892
Local<Value> argv[2];

src/node_internals.h

+35
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,41 @@ class InternalCallbackScope {
503503
bool closed_ = false;
504504
};
505505

506+
class ThreadPoolWork {
507+
public:
508+
explicit inline ThreadPoolWork(Environment* env) : env_(env) {}
509+
inline void ScheduleWork();
510+
inline int CancelWork();
511+
512+
virtual void DoThreadPoolWork() = 0;
513+
virtual void AfterThreadPoolWork(int status) = 0;
514+
515+
private:
516+
Environment* env_;
517+
uv_work_t work_req_;
518+
};
519+
520+
void ThreadPoolWork::ScheduleWork() {
521+
env_->IncreaseWaitingRequestCounter();
522+
int status = uv_queue_work(
523+
env_->event_loop(),
524+
&work_req_,
525+
[](uv_work_t* req) {
526+
ThreadPoolWork* self = ContainerOf(&ThreadPoolWork::work_req_, req);
527+
self->DoThreadPoolWork();
528+
},
529+
[](uv_work_t* req, int status) {
530+
ThreadPoolWork* self = ContainerOf(&ThreadPoolWork::work_req_, req);
531+
self->env_->DecreaseWaitingRequestCounter();
532+
self->AfterThreadPoolWork(status);
533+
});
534+
CHECK_EQ(status, 0);
535+
}
536+
537+
int ThreadPoolWork::CancelWork() {
538+
return uv_cancel(reinterpret_cast<uv_req_t*>(&work_req_));
539+
}
540+
506541
static inline const char *errno_string(int errorno) {
507542
#define ERRNO_CASE(e) case e: return #e;
508543
switch (errorno) {

0 commit comments

Comments
 (0)