@@ -515,19 +515,8 @@ void Message::MemoryInfo(MemoryTracker* tracker) const {
515
515
tracker->TrackField (" transferables" , transferables_);
516
516
}
517
517
518
- // TODO(@jasnell): The name here will be an empty string if the
519
- // one-to-one MessageChannel is used. In such cases,
520
- // SiblingGroup::Get() will return nothing and group_ will be
521
- // an empty pointer. @addaleax suggests that the code here
522
- // could be clearer if attaching the SiblingGroup were a
523
- // separate step rather than part of the constructor here.
524
- MessagePortData::MessagePortData (
525
- MessagePort* owner,
526
- const std::string& name)
527
- : owner_(owner),
528
- group_(SiblingGroup::Get(name)) {
529
- if (group_)
530
- group_->Entangle (this );
518
+ MessagePortData::MessagePortData (MessagePort* owner)
519
+ : owner_(owner) {
531
520
}
532
521
533
522
MessagePortData::~MessagePortData () {
@@ -552,17 +541,13 @@ void MessagePortData::AddToIncomingQueue(std::shared_ptr<Message> message) {
552
541
}
553
542
554
543
void MessagePortData::Entangle (MessagePortData* a, MessagePortData* b) {
555
- CHECK (!a->group_ );
556
- CHECK (!b->group_ );
557
- b->group_ = a->group_ = std::make_shared<SiblingGroup>();
558
- a->group_ ->Entangle (a);
559
- a->group_ ->Entangle (b);
544
+ auto group = std::make_shared<SiblingGroup>();
545
+ group->Entangle ({a, b});
560
546
}
561
547
562
548
void MessagePortData::Disentangle () {
563
549
if (group_) {
564
550
group_->Disentangle (this );
565
- group_.reset ();
566
551
}
567
552
}
568
553
@@ -572,13 +557,12 @@ MessagePort::~MessagePort() {
572
557
573
558
MessagePort::MessagePort (Environment* env,
574
559
Local<Context> context,
575
- Local<Object> wrap,
576
- const std::string& name)
560
+ Local<Object> wrap)
577
561
: HandleWrap(env,
578
562
wrap,
579
563
reinterpret_cast <uv_handle_t *>(&async_),
580
564
AsyncWrap::PROVIDER_MESSAGEPORT),
581
- data_ (new MessagePortData(this , name )) {
565
+ data_ (new MessagePortData(this )) {
582
566
auto onmessage = [](uv_async_t * handle) {
583
567
// Called when data has been put into the queue.
584
568
MessagePort* channel = ContainerOf (&MessagePort::async_, handle);
@@ -645,7 +629,7 @@ MessagePort* MessagePort::New(
645
629
Environment* env,
646
630
Local<Context> context,
647
631
std::unique_ptr<MessagePortData> data,
648
- const std::string& name ) {
632
+ std::shared_ptr<SiblingGroup> sibling_group ) {
649
633
Context::Scope context_scope (context);
650
634
Local<FunctionTemplate> ctor_templ = GetMessagePortConstructorTemplate (env);
651
635
@@ -654,14 +638,15 @@ MessagePort* MessagePort::New(
654
638
Local<Object> instance;
655
639
if (!ctor_templ->InstanceTemplate ()->NewInstance (context).ToLocal (&instance))
656
640
return nullptr ;
657
- MessagePort* port = new MessagePort (env, context, instance, name );
641
+ MessagePort* port = new MessagePort (env, context, instance);
658
642
CHECK_NOT_NULL (port);
659
643
if (port->IsHandleClosing ()) {
660
644
// Construction failed with an exception.
661
645
return nullptr ;
662
646
}
663
647
664
648
if (data) {
649
+ CHECK (!sibling_group);
665
650
port->Detach ();
666
651
port->data_ = std::move (data);
667
652
@@ -673,6 +658,8 @@ MessagePort* MessagePort::New(
673
658
// If the existing MessagePortData object had pending messages, this is
674
659
// the easiest way to run that queue.
675
660
port->TriggerAsync ();
661
+ } else if (sibling_group) {
662
+ sibling_group->Entangle (port->data_ .get ());
676
663
}
677
664
return port;
678
665
}
@@ -1067,7 +1054,7 @@ void MessagePort::MoveToContext(const FunctionCallbackInfo<Value>& args) {
1067
1054
}
1068
1055
1069
1056
void MessagePort::Entangle (MessagePort* a, MessagePort* b) {
1070
- Entangle (a, b->data_ .get ());
1057
+ MessagePortData:: Entangle (a-> data_ . get () , b->data_ .get ());
1071
1058
}
1072
1059
1073
1060
void MessagePort::Entangle (MessagePort* a, MessagePortData* b) {
@@ -1274,7 +1261,6 @@ Maybe<bool> JSTransferable::Data::FinalizeTransferWrite(
1274
1261
}
1275
1262
1276
1263
std::shared_ptr<SiblingGroup> SiblingGroup::Get (const std::string& name) {
1277
- if (name.empty ()) return {};
1278
1264
Mutex::ScopedLock lock (SiblingGroup::groups_mutex_);
1279
1265
std::shared_ptr<SiblingGroup> group;
1280
1266
auto i = groups_.find (name);
@@ -1348,14 +1334,24 @@ Maybe<bool> SiblingGroup::Dispatch(
1348
1334
return Just (true );
1349
1335
}
1350
1336
1351
- void SiblingGroup::Entangle (MessagePortData* data) {
1337
+ void SiblingGroup::Entangle (MessagePortData* port) {
1338
+ Entangle ({ port });
1339
+ }
1340
+
1341
+ void SiblingGroup::Entangle (std::initializer_list<MessagePortData*> ports) {
1352
1342
Mutex::ScopedLock lock (group_mutex_);
1353
- ports_.insert (data);
1343
+ for (MessagePortData* data : ports) {
1344
+ ports_.insert (data);
1345
+ CHECK (!data->group_ );
1346
+ data->group_ = shared_from_this ();
1347
+ }
1354
1348
}
1355
1349
1356
1350
void SiblingGroup::Disentangle (MessagePortData* data) {
1351
+ auto self = shared_from_this (); // Keep alive until end of function.
1357
1352
Mutex::ScopedLock lock (group_mutex_);
1358
1353
ports_.erase (data);
1354
+ data->group_ .reset ();
1359
1355
1360
1356
data->AddToIncomingQueue (std::make_shared<Message>());
1361
1357
// If this is an anonymous group and there's another port, close it.
@@ -1407,8 +1403,10 @@ static void BroadcastChannel(const FunctionCallbackInfo<Value>& args) {
1407
1403
Context::Scope context_scope (env->context ());
1408
1404
Utf8Value name (env->isolate (), args[0 ]);
1409
1405
MessagePort* port =
1410
- MessagePort::New (env, env->context (), nullptr , std::string (*name));
1411
- args.GetReturnValue ().Set (port->object ());
1406
+ MessagePort::New (env, env->context (), {}, SiblingGroup::Get (*name));
1407
+ if (port != nullptr ) {
1408
+ args.GetReturnValue ().Set (port->object ());
1409
+ }
1412
1410
}
1413
1411
1414
1412
static void InitMessaging (Local<Object> target,
0 commit comments