diff options
Diffstat (limited to 'erts/emulator/beam/erl_monitor_link.c')
-rw-r--r-- | erts/emulator/beam/erl_monitor_link.c | 95 |
1 files changed, 87 insertions, 8 deletions
diff --git a/erts/emulator/beam/erl_monitor_link.c b/erts/emulator/beam/erl_monitor_link.c index 43028be39d..7b3010bab2 100644 --- a/erts/emulator/beam/erl_monitor_link.c +++ b/erts/emulator/beam/erl_monitor_link.c @@ -540,6 +540,7 @@ erts_mon_link_dist_create(Eterm nodename) mld->links = NULL; mld->monitors = NULL; mld->orig_name_monitors = NULL; + mld->dist_pend_spawn_exit = NULL; return mld; } @@ -551,6 +552,7 @@ erts_mon_link_dist_destroy__(ErtsMonLnkDist *mld) ERTS_ML_ASSERT(!mld->links); ERTS_ML_ASSERT(!mld->monitors); ERTS_ML_ASSERT(!mld->orig_name_monitors); + ERTS_ML_ASSERT(!mld->dist_pend_spawn_exit); erts_mtx_destroy(&mld->mtx); erts_free(ERTS_ALC_T_ML_DIST, mld); @@ -834,10 +836,29 @@ erts_monitor_create(Uint16 type, Eterm ref, Eterm orgn, Eterm trgt, Eterm name) Uint rsz, osz, tsz; Eterm *hp; ErlOffHeap oh; - Uint16 name_flag = is_nil(name) ? ((Uint16) 0) : ERTS_ML_FLG_NAME; + Uint16 name_flag; + Uint16 pending_flag; rsz = is_immed(ref) ? 0 : size_object(ref); - tsz = is_immed(trgt) ? 0 : size_object(trgt); + if (trgt != am_pending) { + if (is_not_immed(trgt)) + tsz = size_object(trgt); + else + tsz = 0; + pending_flag = (Uint16) 0; + name_flag = is_nil(name) ? ((Uint16) 0) : ERTS_ML_FLG_NAME; + } + else { + /* Pending spawn_request() */ + pending_flag = ERTS_ML_FLG_SPAWN_PENDING; + /* Prepare for storage of exteral pid */ + tsz = EXTERNAL_THING_HEAD_SIZE + 1; + /* name contains tag */ + + /* Not by name */ + name_flag = (Uint16) 0; + + } if (type == ERTS_MON_TYPE_RESOURCE) osz = 0; else @@ -851,6 +872,16 @@ erts_monitor_create(Uint16 type, Eterm ref, Eterm orgn, Eterm trgt, Eterm name) hp = &mdep->heap[0]; + if (pending_flag) { + /* Make room for the future pid... */ +#ifdef DEBUG + int i; + for (i = 0; i < EXTERNAL_THING_HEAD_SIZE + 1; i++) + hp[i] = THE_NON_VALUE; +#endif + hp += EXTERNAL_THING_HEAD_SIZE + 1; + } + mdp = &mdep->md; ERTS_ML_ASSERT(((void *) mdp) == ((void *) mdep)); @@ -858,7 +889,7 @@ erts_monitor_create(Uint16 type, Eterm ref, Eterm orgn, Eterm trgt, Eterm name) mdp->origin.other.item = tsz ? copy_struct(trgt, tsz, &hp, &oh) : trgt; mdp->origin.offset = (Uint16) offsetof(ErtsMonitorData, origin); - mdp->origin.flags = ERTS_ML_FLG_EXTENDED|name_flag; + mdp->origin.flags = ERTS_ML_FLG_EXTENDED|name_flag|pending_flag; mdp->origin.type = type; if (type == ERTS_MON_TYPE_RESOURCE) @@ -878,6 +909,25 @@ erts_monitor_create(Uint16 type, Eterm ref, Eterm orgn, Eterm trgt, Eterm name) } else { mdep->u.name = name; + if (pending_flag) { + /* spawn_request() tag is in 'name' */ + if (is_not_immed(name)) { + /* + * Save the tag in its own heap fragment with a + * little trick: + * + * bp->mem[0] = The tag + * bp->mem[1] = Beginning of heap + * mdep->u.name = Countinuation pointer to + * heap fragment... + */ + Uint hsz = size_object(name)+1; + ErlHeapFragment *bp = new_message_buffer(hsz); + Eterm *hp = &bp->mem[1]; + bp->mem[0] = copy_struct(name, hsz-1, &hp, &bp->off_heap); + mdep->u.name = make_cp((void*)bp); + } + } mdp->origin.key_offset = (Uint16) offsetof(ErtsMonitorData, ref); ERTS_ML_ASSERT(mdp->origin.key_offset >= mdp->origin.offset); @@ -964,6 +1014,20 @@ erts_monitor_destroy__(ErtsMonitorData *mdp) } if (mdep->dist) erts_mon_link_dist_dec_refc(mdep->dist); + if (mdp->origin.flags & ERTS_ML_FLG_SPAWN_PENDING) { + /* + * We have the spawn_request() tag stored in + * mdep->u.name via a little trick + * (see pending_flag in erts_monitor_create()). + * If non-immediate value make sure to release + * this heap fragment as well. + */ + if (is_not_immed(mdep->u.name)) { + ErlHeapFragment *bp; + bp = (ErlHeapFragment *) cp_val(mdep->u.name); + free_message_buffer(bp); + } + } erts_free(ERTS_ALC_T_MONITOR_EXT, mdp); } } @@ -1248,11 +1312,26 @@ erts_link_create(Uint16 type, Eterm a, Eterm b) Eterm *hp; ErlOffHeap oh; - if (is_internal_pid(a)) - hsz = NC_HEAP_SIZE(b); - else - hsz = NC_HEAP_SIZE(a); - ERTS_ML_ASSERT(hsz > 0); + hsz = EXTERNAL_THING_HEAD_SIZE + 1; + if (hsz < ERTS_REF_THING_SIZE + && (is_internal_ordinary_ref(a) + || is_internal_ordinary_ref(b))) { + hsz = ERTS_REF_THING_SIZE; + } + +#ifdef DEBUG + if (is_internal_pid(a)) { + ERTS_ML_ASSERT(is_external_pid(b) + || is_internal_ordinary_ref(b)); + ERTS_ML_ASSERT(NC_HEAP_SIZE(b) <= hsz); + } + else { + ERTS_ML_ASSERT(is_internal_pid(b)); + ERTS_ML_ASSERT(is_external_pid(a) + || is_internal_ordinary_ref(a)); + ERTS_ML_ASSERT(NC_HEAP_SIZE(a) <= hsz); + } +#endif size = sizeof(ErtsLinkDataExtended) - sizeof(Eterm); size += hsz*sizeof(Eterm); |