@@ -34,6 +34,7 @@ using v8::HandleScope;
3434using v8::Integer;
3535using v8::Isolate;
3636using v8::Local;
37+ using v8::LocalVector;
3738using v8::Locker;
3839using v8::Maybe;
3940using v8::Name;
@@ -221,6 +222,8 @@ class WorkerThreadData {
221222 }
222223
223224 ~WorkerThreadData () {
225+ Worker::UnregisterAllNotifications (isolate_data_.get ());
226+
224227 Debug (w_, " Worker %llu dispose isolate" , w_->thread_id_ .id );
225228 Isolate* isolate;
226229 {
@@ -1281,6 +1284,127 @@ void Worker::LoopStartTime(const FunctionCallbackInfo<Value>& args) {
12811284 args.GetReturnValue ().Set (loop_start_time / 1e6 );
12821285}
12831286
1287+ void Worker::GetNotifications (const FunctionCallbackInfo<Value>& args) {
1288+ Environment* env = Environment::GetCurrent (args);
1289+ Isolate* isolate = env->isolate ();
1290+ LocalVector<Value> notifications (isolate);
1291+
1292+ for (auto notification_id : env->isolate_data ()->worker_notifications_ ) {
1293+ notifications.push_back (v8::BigInt::New (isolate, notification_id));
1294+ }
1295+
1296+ args.GetReturnValue ().Set (
1297+ Array::New (isolate, notifications.data (), notifications.size ()));
1298+ }
1299+
1300+ void Worker::RegisterNotification (const FunctionCallbackInfo<Value>& args) {
1301+ CHECK (args[0 ]->IsFunction ());
1302+
1303+ Environment* env = Environment::GetCurrent (args);
1304+ Isolate* isolate = env->isolate ();
1305+ NotificationData* notification =
1306+ new NotificationData (env->thread_id (), env, args[0 ].As <v8::Function>());
1307+
1308+ notification->Register (env->isolate_data ());
1309+ args.GetReturnValue ().Set (v8::BigInt::New (isolate, notification->id_ ));
1310+ }
1311+
1312+ void Worker::SendNotification (const FunctionCallbackInfo<Value>& args) {
1313+ CHECK (args[0 ]->IsBigInt ());
1314+
1315+ uint64_t notification_id = args[0 ].As <v8::BigInt>()->Uint64Value ();
1316+ NotificationData* notification = workers_notifications_[notification_id];
1317+
1318+ if (notification == nullptr ) {
1319+ return THROW_ERR_INVALID_NOTIFICATION (
1320+ args.GetIsolate (), " Invalid notification %llun" , notification_id);
1321+ }
1322+
1323+ uv_async_send (¬ification->async_ );
1324+ }
1325+
1326+ void Worker::UnregisterNotification (const FunctionCallbackInfo<Value>& args) {
1327+ CHECK (args[0 ]->IsBigInt ());
1328+
1329+ Environment* env = Environment::GetCurrent (args);
1330+ uint64_t notification_id = args[0 ].As <v8::BigInt>()->Uint64Value ();
1331+ NotificationData* notification = workers_notifications_[notification_id];
1332+
1333+ if (notification == nullptr || notification->thread_id_ != env->thread_id ()) {
1334+ return THROW_ERR_INVALID_NOTIFICATION (
1335+ args.GetIsolate (), " Invalid notification %un" , notification_id);
1336+ }
1337+
1338+ notification->Unregister (env->isolate_data ());
1339+ }
1340+
1341+ void Worker::UnregisterNotifications (const FunctionCallbackInfo<Value>& args) {
1342+ UnregisterAllNotifications (Environment::GetCurrent (args)->isolate_data ());
1343+ }
1344+
1345+ void Worker::UnregisterAllNotifications (IsolateData* isolate_data) {
1346+ for (auto notification_id : isolate_data->worker_notifications_ ) {
1347+ workers_notifications_[notification_id]->Unregister (isolate_data);
1348+ }
1349+
1350+ // Wait for the uv_close callbacks to trigger
1351+ if (!isolate_data->worker_notifications_ .empty ()) {
1352+ uv_run (isolate_data->event_loop (), UV_RUN_ONCE);
1353+ }
1354+
1355+ isolate_data->worker_notifications_ .clear ();
1356+ }
1357+
1358+ NotificationData::NotificationData (uint64_t thread_id,
1359+ Environment* env,
1360+ v8::Local<v8::Function> callback)
1361+ : id_(++notifications_counter_), thread_id_(thread_id), env_(env) {
1362+ this ->async_ .data = this ;
1363+ this ->callback_ .Reset (env->isolate (), callback);
1364+ }
1365+
1366+ NotificationData::~NotificationData () {
1367+ workers_notifications_.erase (this ->id_ );
1368+
1369+ if (!this ->callback_ .IsEmpty ()) {
1370+ this ->callback_ .Reset ();
1371+ }
1372+ }
1373+
1374+ void NotificationData::Register (IsolateData* isolate_data) {
1375+ isolate_data->worker_notifications_ .insert (this ->id_ );
1376+ workers_notifications_.emplace (this ->id_ , this );
1377+
1378+ uv_async_init (env_->event_loop (), &this ->async_ , [](uv_async_t * handle) {
1379+ reinterpret_cast <NotificationData*>(handle->data )->Execute ();
1380+ });
1381+ }
1382+
1383+ void NotificationData::Unregister (IsolateData* isolate_data) {
1384+ uv_close (reinterpret_cast <uv_handle_t *>(&this ->async_ ),
1385+ [](uv_handle_t * handle) {
1386+ NotificationData* notification =
1387+ reinterpret_cast <NotificationData*>(handle->data );
1388+ delete notification;
1389+ });
1390+
1391+ // Wait for the uv_close callbacks to trigger
1392+ uv_run (isolate_data->event_loop (), UV_RUN_ONCE);
1393+
1394+ isolate_data->worker_notifications_ .erase (this ->id_ );
1395+ workers_notifications_.erase (this ->id_ );
1396+ }
1397+
1398+ void NotificationData::Execute () {
1399+ this ->env_ ->SetImmediate (
1400+ [this ](Environment* env) {
1401+ v8::Isolate* isolate = this ->env_ ->isolate ();
1402+ this ->callback_ .Get (isolate)->Call (
1403+ isolate->GetCurrentContext (), Null (isolate), 0 , nullptr );
1404+ },
1405+ CallbackFlags::kUnrefed );
1406+ }
1407+
12841408namespace {
12851409
12861410// Return the MessagePort that is global for this Environment and communicates
@@ -1380,6 +1504,19 @@ void CreateWorkerPerIsolateProperties(IsolateData* isolate_data,
13801504 }
13811505
13821506 SetMethod (isolate, target, " getEnvMessagePort" , GetEnvMessagePort);
1507+
1508+ SetMethod (isolate, target, " getNotifications" , Worker::GetNotifications);
1509+ SetMethod (
1510+ isolate, target, " registerNotification" , Worker::RegisterNotification);
1511+ SetMethod (isolate, target, " sendNotification" , Worker::SendNotification);
1512+ SetMethod (isolate,
1513+ target,
1514+ " unregisterNotification" ,
1515+ Worker::UnregisterNotification);
1516+ SetMethod (isolate,
1517+ target,
1518+ " unregisterNotifications" ,
1519+ Worker::UnregisterNotifications);
13831520}
13841521
13851522void CreateWorkerPerContextProperties (Local<Object> target,
@@ -1458,6 +1595,11 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
14581595 registry->Register (Worker::CpuUsage);
14591596 registry->Register (Worker::StartCpuProfile);
14601597 registry->Register (Worker::StopCpuProfile);
1598+ registry->Register (Worker::GetNotifications);
1599+ registry->Register (Worker::RegisterNotification);
1600+ registry->Register (Worker::SendNotification);
1601+ registry->Register (Worker::UnregisterNotification);
1602+ registry->Register (Worker::UnregisterNotifications);
14611603}
14621604
14631605} // anonymous namespace
0 commit comments