Пример #1
0
Eterm
erts_msg_distext2heap(Process *pp,
		      ErtsProcLocks *plcksp,
		      ErlHeapFragment **bpp,
		      Eterm *tokenp,
		      ErtsDistExternal *dist_extp)
{
    Eterm msg;
    Uint tok_sz = 0;
    Eterm *hp = NULL;
    ErtsHeapFactory factory;
    Sint sz;

    *bpp = NULL;
    sz = erts_decode_dist_ext_size(dist_extp);
    if (sz < 0)
	goto decode_error;
    if (is_not_nil(*tokenp)) {
	ErlHeapFragment *heap_frag = erts_dist_ext_trailer(dist_extp);
	tok_sz = heap_frag->used_size;
	sz += tok_sz;
    }
    if (pp) {
	ErlOffHeap *ohp;
	hp = erts_alloc_message_heap(sz, bpp, &ohp, pp, plcksp);
    }
    else {
	*bpp = new_message_buffer(sz);
	hp = (*bpp)->mem;
    }
    erts_factory_message_init(&factory, pp, hp, *bpp);
    msg = erts_decode_dist_ext(&factory, dist_extp);
    if (is_non_value(msg))
	goto decode_error;
    if (is_not_nil(*tokenp)) {
	ErlHeapFragment *heap_frag = erts_dist_ext_trailer(dist_extp);
	hp = erts_produce_heap(&factory, tok_sz, 0);
	*tokenp = copy_struct(*tokenp, tok_sz, &hp, factory.off_heap);
	erts_cleanup_offheap(&heap_frag->off_heap);
    }
    erts_free_dist_ext_copy(dist_extp);
    erts_factory_close(&factory);
    return msg;

 decode_error:
    if (is_not_nil(*tokenp)) {
	ErlHeapFragment *heap_frag = erts_dist_ext_trailer(dist_extp);
	erts_cleanup_offheap(&heap_frag->off_heap);
    }
    erts_free_dist_ext_copy(dist_extp);
    *bpp = NULL;
    return THE_NON_VALUE;
 }
Пример #2
0
void
erts_deliver_exit_message(Eterm from, Process *to, ErtsProcLocks *to_locksp,
			  Eterm reason, Eterm token)
{
    Eterm mess;
    Eterm save;
    Eterm from_copy;
    Uint sz_reason;
    Uint sz_token;
    Uint sz_from;
    Eterm* hp;
    Eterm temptoken;
    ErlHeapFragment* bp = NULL;

    if (token != NIL
#ifdef USE_VM_PROBES
	&& token != am_have_dt_utag
#endif
	) {

	ASSERT(is_tuple(token));
	sz_reason = size_object(reason);
	sz_token = size_object(token);
	sz_from = size_object(from);
	bp = new_message_buffer(sz_reason + sz_from + sz_token + 4);
	hp = bp->mem;
	mess = copy_struct(reason, sz_reason, &hp, &bp->off_heap);
	from_copy = copy_struct(from, sz_from, &hp, &bp->off_heap);
	save = TUPLE3(hp, am_EXIT, from_copy, mess);
	hp += 4;
	/* the trace token must in this case be updated by the caller */
	seq_trace_output(token, save, SEQ_TRACE_SEND, to->common.id, NULL);
	temptoken = copy_struct(token, sz_token, &hp, &bp->off_heap);
	erts_queue_message(to, to_locksp, bp, save, temptoken);
    } else {
	ErlOffHeap *ohp;
	sz_reason = size_object(reason);
	sz_from = IS_CONST(from) ? 0 : size_object(from);

	hp = erts_alloc_message_heap(sz_reason+sz_from+4,
				     &bp,
				     &ohp,
				     to,
				     to_locksp);

	mess = copy_struct(reason, sz_reason, &hp, ohp);
	from_copy = (IS_CONST(from)
		     ? from
		     : copy_struct(from, sz_from, &hp, ohp));
	save = TUPLE3(hp, am_EXIT, from_copy, mess);
	erts_queue_message(to, to_locksp, bp, save, NIL);
    }
}
Пример #3
0
static void notify_proc(Process *proc, Eterm ref, Eterm driver_name, Eterm type, 
			Eterm tag, int errcode)
{
    Eterm mess;
    Eterm r;
    Eterm *hp;
    ErtsMessage *mp;
    ErtsProcLocks rp_locks = 0;
    ErlOffHeap *ohp;
    ERTS_CHK_NO_PROC_LOCKS;

    assert_drv_list_rwlocked();
    if (errcode != 0) {
	int need = load_error_need(errcode);
	Eterm e;
	mp = erts_alloc_message_heap(proc, &rp_locks,
				     (6 /* tuple */ + 3 /* Error tuple */ + 
				      ERTS_REF_THING_SIZE + need),
				     &hp, &ohp);
	r = copy_ref(ref,hp);
	hp += ERTS_REF_THING_SIZE;
	e = build_load_error_hp(hp, errcode);
	hp += need;
	mess = TUPLE2(hp,tag,e);
	hp += 3;
	mess = TUPLE5(hp,type,r,am_driver,driver_name,mess);
    } else {	
	mp = erts_alloc_message_heap(proc, &rp_locks,
				     6 /* tuple */ + ERTS_REF_THING_SIZE,
				     &hp, &ohp);
	r = copy_ref(ref,hp);
	hp += ERTS_REF_THING_SIZE;
	mess = TUPLE5(hp,type,r,am_driver,driver_name,tag);
    }
    erts_queue_message(proc, rp_locks, mp, mess, am_system);
    erts_proc_unlock(proc, rp_locks);
    ERTS_CHK_NO_PROC_LOCKS;
}
Пример #4
0
static void send_reply(ErtsMsAcc *msacc, ErtsMSAccReq *msaccrp) {
    ErtsSchedulerData *esdp = erts_get_scheduler_data();
    Process *rp = msaccrp->proc;
    ErtsMessage *msgp = NULL;
    Eterm **hpp, *hp;
    Eterm ref_copy = NIL, msg;
    Uint sz, *szp;
    ErlOffHeap *ohp = NULL;
    ErtsProcLocks rp_locks = (esdp && msaccrp->req_sched == esdp->no
                              ? ERTS_PROC_LOCK_MAIN : 0);

    sz = 0;
    hpp = NULL;
    szp = &sz;

    if (msacc->unmanaged) erts_mtx_lock(&msacc->mtx);

    while (1) {
	if (hpp)
            ref_copy = STORE_NC(hpp, ohp, msaccrp->ref);
	else
            *szp += REF_THING_SIZE;

	if (msaccrp->action != ERTS_MSACC_GATHER)
            msg = ref_copy;
	else {
            msg = erts_msacc_gather_stats(msacc, hpp, szp);
            msg = erts_bld_tuple(hpp, szp, 2, ref_copy, msg);
	}
	if (hpp)
            break;

	msgp = erts_alloc_message_heap(rp, &rp_locks, sz, &hp, &ohp);
        hpp = &hp;
	szp = NULL;
    }

    if (msacc->unmanaged) erts_mtx_unlock(&msacc->mtx);

    erts_queue_message(rp, rp_locks, msgp, msg, am_system);

    if (esdp && msaccrp->req_sched == esdp->no)
	rp_locks &= ~ERTS_PROC_LOCK_MAIN;

    if (rp_locks)
	erts_smp_proc_unlock(rp, rp_locks);

}
Пример #5
0
Файл: sys.c Проект: weisslj/otp
static void signal_notify_requested(Eterm type) {
    Process* p = NULL;
    Eterm msg, *hp;
    ErtsProcLocks locks = 0;
    ErlOffHeap *ohp;

    Eterm id = erts_whereis_name_to_id(NULL, am_erl_signal_server);

    if ((p = (erts_pid2proc_opt(NULL, 0, id, 0, ERTS_P2P_FLG_INC_REFC))) != NULL) {
        ErtsMessage *msgp = erts_alloc_message_heap(p, &locks, 3, &hp, &ohp);

        /* erl_signal_server ! {notify, sighup} */
        msg = TUPLE2(hp, am_notify, type);
        erts_queue_message(p, locks, msgp, msg, am_system);

        if (locks)
            erts_smp_proc_unlock(p, locks);
        erts_proc_dec_refc(p);
    }
}
Пример #6
0
static int
dirty_send_message(Process *c_p, Eterm to, Eterm tag)
{
    ErtsProcLocks c_p_locks, rp_locks;
    Process *rp, *real_c_p;
    Eterm msg, *hp;
    ErlOffHeap *ohp;
    ErtsMessage *mp;

    ASSERT(is_immed(tag));

    real_c_p = erts_proc_shadow2real(c_p);
    if (real_c_p != c_p)
	c_p_locks = 0;
    else
	c_p_locks = ERTS_PROC_LOCK_MAIN;

    ASSERT(real_c_p->common.id == c_p->common.id);

    rp = erts_pid2proc_opt(real_c_p, c_p_locks,
			   to, 0,
			   ERTS_P2P_FLG_INC_REFC);

    if (!rp)
	return 0;

    rp_locks = 0;
    mp = erts_alloc_message_heap(rp, &rp_locks, 3, &hp, &ohp);

    msg = TUPLE2(hp, tag, c_p->common.id);
    erts_queue_message(rp, rp_locks, mp, msg, c_p->common.id);

    if (rp == real_c_p)
	rp_locks &= ~c_p_locks;
    if (rp_locks)
	erts_proc_unlock(rp, rp_locks);

    erts_proc_dec_refc(rp);

    return 1;
}
Пример #7
0
static void send_reply(ErtsMsAcc *msacc, ErtsMSAccReq *msaccrp) {
    ErtsSchedulerData *esdp = erts_get_scheduler_data();
    Process *rp = msaccrp->proc;
    ErtsMessage *msgp = NULL;
    Eterm *hp;
    Eterm ref_copy = NIL, msg;
    ErtsProcLocks rp_locks = (esdp && msaccrp->req_sched == esdp->no
                              ? ERTS_PROC_LOCK_MAIN : 0);
    ErtsHeapFactory factory;

    if (msaccrp->action == ERTS_MSACC_GATHER) {

        msgp = erts_factory_message_create(&factory, rp, &rp_locks, DEFAULT_MSACC_MSG_SIZE);

        if (msacc->unmanaged) erts_mtx_lock(&msacc->mtx);

        hp = erts_produce_heap(&factory, REF_THING_SIZE + 3 /* tuple */, 0);
        ref_copy = STORE_NC(&hp, &msgp->hfrag.off_heap, msaccrp->ref);
        msg = erts_msacc_gather_stats(msacc, &factory);
        msg = TUPLE2(hp, ref_copy, msg);

        if (msacc->unmanaged) erts_mtx_unlock(&msacc->mtx);

        erts_factory_close(&factory);
    } else {
        ErlOffHeap *ohp = NULL;
        msgp = erts_alloc_message_heap(rp, &rp_locks, REF_THING_SIZE, &hp, &ohp);
        msg = STORE_NC(&hp, &msgp->hfrag.off_heap, msaccrp->ref);
    }

    erts_queue_message(rp, rp_locks, msgp, msg, am_system);

    if (esdp && msaccrp->req_sched == esdp->no)
	rp_locks &= ~ERTS_PROC_LOCK_MAIN;

    if (rp_locks)
	erts_smp_proc_unlock(rp, rp_locks);

}
Пример #8
0
void
erts_deliver_exit_message(Eterm from, Process *to, ErtsProcLocks *to_locksp,
			  Eterm reason, Eterm token)
{
    Eterm mess;
    Eterm save;
    Eterm from_copy;
    Uint sz_reason;
    Uint sz_token;
    Uint sz_from;
    Eterm* hp;
    Eterm temptoken;
    ErtsMessage* mp;
    ErlOffHeap *ohp;
#ifdef SHCOPY_SEND
    erts_shcopy_t info;
#endif

    if (have_seqtrace(token)) {
	ASSERT(is_tuple(token));
	sz_token = size_object(token);
	sz_from = size_object(from);
#ifdef SHCOPY_SEND
        INITIALIZE_SHCOPY(info);
        sz_reason = copy_shared_calculate(reason, &info);
#else
	sz_reason = size_object(reason);
#endif
	mp = erts_alloc_message_heap(to, to_locksp,
				     sz_reason + sz_from + sz_token + 4,
				     &hp, &ohp);
#ifdef SHCOPY_SEND
        mess = copy_shared_perform(reason, sz_reason, &info, &hp, ohp);
        DESTROY_SHCOPY(info);
#else
	mess = copy_struct(reason, sz_reason, &hp, ohp);
#endif
	from_copy = copy_struct(from, sz_from, &hp, ohp);
	save = TUPLE3(hp, am_EXIT, from_copy, mess);
	hp += 4;
	/* the trace token must in this case be updated by the caller */
	seq_trace_output(token, save, SEQ_TRACE_SEND, to->common.id, NULL);
	temptoken = copy_struct(token, sz_token, &hp, ohp);
        ERL_MESSAGE_TOKEN(mp) = temptoken;
	erts_queue_message(to, *to_locksp, mp, save, am_system);
    } else {
	sz_from = IS_CONST(from) ? 0 : size_object(from);
#ifdef SHCOPY_SEND
        INITIALIZE_SHCOPY(info);
        sz_reason = copy_shared_calculate(reason, &info);
#else
	sz_reason = size_object(reason);
#endif
	mp = erts_alloc_message_heap(to, to_locksp,
				     sz_reason+sz_from+4, &hp, &ohp);

#ifdef SHCOPY_SEND
        mess = copy_shared_perform(reason, sz_reason, &info, &hp, ohp);
        DESTROY_SHCOPY(info);
#else
	mess = copy_struct(reason, sz_reason, &hp, ohp);
#endif
	from_copy = (IS_CONST(from)
		     ? from
		     : copy_struct(from, sz_from, &hp, ohp));
	save = TUPLE3(hp, am_EXIT, from_copy, mess);
	erts_queue_message(to, *to_locksp, mp, save, am_system);
    }
}
Пример #9
0
void
erts_send_message(Process* sender,
                  Process* receiver,
                  ErtsProcLocks *receiver_locks,
                  Eterm message,
                  unsigned flags)
{
    Uint msize;
    ErlHeapFragment* bp = NULL;
    Eterm token = NIL;
#ifdef USE_VM_PROBES
    DTRACE_CHARBUF(sender_name, 64);
    DTRACE_CHARBUF(receiver_name, 64);
    Sint tok_label = 0;
    Sint tok_lastcnt = 0;
    Sint tok_serial = 0;
#endif
    BM_STOP_TIMER(system);
    BM_MESSAGE(message,sender,receiver);
    BM_START_TIMER(send);

#ifdef USE_VM_PROBES
    *sender_name = *receiver_name = '\0';
    if (DTRACE_ENABLED(message_send)) {
        erts_snprintf(sender_name, sizeof(DTRACE_CHARBUF_NAME(sender_name)), "%T", sender->id);
        erts_snprintf(receiver_name, sizeof(DTRACE_CHARBUF_NAME(receiver_name)), "%T", receiver->id);
    }
#endif
    if (SEQ_TRACE_TOKEN(sender) != NIL && !(flags & ERTS_SND_FLG_NO_SEQ_TRACE)) {
        Eterm* hp;
        Eterm stoken = SEQ_TRACE_TOKEN(sender);
        Uint seq_trace_size = 0;
#ifdef USE_VM_PROBES
        Uint dt_utag_size = 0;
        Eterm utag = NIL;
#endif

        BM_SWAP_TIMER(send,size);
        msize = size_object(message);
        BM_SWAP_TIMER(size,send);

#ifdef USE_VM_PROBES
        if (stoken != am_have_dt_utag) {
#endif

            seq_trace_update_send(sender);
            seq_trace_output(stoken, message, SEQ_TRACE_SEND,
                             receiver->id, sender);
            seq_trace_size = 6; /* TUPLE5 */
#ifdef USE_VM_PROBES
        }
        if (DT_UTAG_FLAGS(sender) & DT_UTAG_SPREADING) {
            dt_utag_size = size_object(DT_UTAG(sender));
        } else if (stoken == am_have_dt_utag ) {
            stoken = NIL;
        }
#endif

        bp = new_message_buffer(msize + seq_trace_size
#ifdef USE_VM_PROBES
                                + dt_utag_size
#endif
                               );
        hp = bp->mem;

        BM_SWAP_TIMER(send,copy);
        token = copy_struct(stoken,
                            seq_trace_size,
                            &hp,
                            &bp->off_heap);

        message = copy_struct(message, msize, &hp, &bp->off_heap);
#ifdef USE_VM_PROBES
        if (DT_UTAG_FLAGS(sender) & DT_UTAG_SPREADING) {
            utag = copy_struct(DT_UTAG(sender), dt_utag_size, &hp, &bp->off_heap);
#ifdef DTRACE_TAG_HARDDEBUG
            erts_fprintf(stderr,
                         "Dtrace -> (%T) Spreading tag (%T) with "
                         "message %T!\r\n",sender->id, utag, message);
#endif
        }
#endif
        BM_MESSAGE_COPIED(msize);
        BM_SWAP_TIMER(copy,send);

#ifdef USE_VM_PROBES
        if (DTRACE_ENABLED(message_send)) {
            if (stoken != NIL && stoken != am_have_dt_utag) {
                tok_label = signed_val(SEQ_TRACE_T_LABEL(stoken));
                tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(stoken));
                tok_serial = signed_val(SEQ_TRACE_T_SERIAL(stoken));
            }
            DTRACE6(message_send, sender_name, receiver_name,
                    msize, tok_label, tok_lastcnt, tok_serial);
        }
#endif
        erts_queue_message(receiver,
                           receiver_locks,
                           bp,
                           message,
                           token
#ifdef USE_VM_PROBES
                           , utag
#endif
                          );
        BM_SWAP_TIMER(send,system);
    } else if (sender == receiver) {
        /* Drop message if receiver has a pending exit ... */
#ifdef ERTS_SMP
        ErtsProcLocks need_locks = (~(*receiver_locks)
                                    & (ERTS_PROC_LOCK_MSGQ
                                       | ERTS_PROC_LOCK_STATUS));
        if (need_locks) {
            *receiver_locks |= need_locks;
            if (erts_smp_proc_trylock(receiver, need_locks) == EBUSY) {
                if (need_locks == ERTS_PROC_LOCK_MSGQ) {
                    erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_STATUS);
                    need_locks = ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS;
                }
                erts_smp_proc_lock(receiver, need_locks);
            }
        }
        if (!ERTS_PROC_PENDING_EXIT(receiver))
#endif
        {
            ErlMessage* mp = message_alloc();

            DTRACE6(message_send, sender_name, receiver_name,
                    size_object(message), tok_label, tok_lastcnt, tok_serial);
            mp->data.attached = NULL;
            ERL_MESSAGE_TERM(mp) = message;
            ERL_MESSAGE_TOKEN(mp) = NIL;
#ifdef USE_VM_PROBES
            ERL_MESSAGE_DT_UTAG(mp) = NIL;
#endif
            mp->next = NULL;
            /*
             * We move 'in queue' to 'private queue' and place
             * message at the end of 'private queue' in order
             * to ensure that the 'in queue' doesn't contain
             * references into the heap. By ensuring this,
             * we don't need to include the 'in queue' in
             * the root set when garbage collecting.
             */

            ERTS_SMP_MSGQ_MV_INQ2PRIVQ(receiver);
            LINK_MESSAGE_PRIVQ(receiver, mp);

            if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)) {
                trace_receive(receiver, message);
            }
        }
        BM_SWAP_TIMER(send,system);
        return;
    } else {
#ifdef ERTS_SMP
        ErlOffHeap *ohp;
        Eterm *hp;
        BM_SWAP_TIMER(send,size);
        msize = size_object(message);
        BM_SWAP_TIMER(size,send);
        hp = erts_alloc_message_heap(msize,&bp,&ohp,receiver,receiver_locks);
        BM_SWAP_TIMER(send,copy);
        message = copy_struct(message, msize, &hp, ohp);
        BM_MESSAGE_COPIED(msz);
        BM_SWAP_TIMER(copy,send);
        DTRACE6(message_send, sender_name, receiver_name,
                msize, tok_label, tok_lastcnt, tok_serial);
        erts_queue_message(receiver, receiver_locks, bp, message, token
#ifdef USE_VM_PROBES
                           , NIL
#endif
                          );
        BM_SWAP_TIMER(send,system);
#else
        ErlMessage* mp = message_alloc();
        Eterm *hp;
        BM_SWAP_TIMER(send,size);
        msize = size_object(message);
        BM_SWAP_TIMER(size,send);

        if (receiver->stop - receiver->htop <= msize) {
            BM_SWAP_TIMER(send,system);
            erts_garbage_collect(receiver, msize, receiver->arg_reg, receiver->arity);
            BM_SWAP_TIMER(system,send);
        }
        hp = receiver->htop;
        receiver->htop = hp + msize;
        BM_SWAP_TIMER(send,copy);
        message = copy_struct(message, msize, &hp, &receiver->off_heap);
        BM_MESSAGE_COPIED(msize);
        BM_SWAP_TIMER(copy,send);
        DTRACE6(message_send, sender_name, receiver_name,
                (uint32_t)msize, tok_label, tok_lastcnt, tok_serial);
        ERL_MESSAGE_TERM(mp) = message;
        ERL_MESSAGE_TOKEN(mp) = NIL;
#ifdef USE_VM_PROBES
        ERL_MESSAGE_DT_UTAG(mp) = NIL;
#endif
        mp->next = NULL;
        mp->data.attached = NULL;
        LINK_MESSAGE(receiver, mp);

        if (receiver->status == P_WAITING) {
            erts_add_to_runq(receiver);
        } else if (receiver->status == P_SUSPENDED) {
            receiver->rstatus = P_RUNABLE;
        }
        if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)) {
            trace_receive(receiver, message);
        }
        BM_SWAP_TIMER(send,system);
#endif /* #ifndef ERTS_SMP */
        return;
    }
}
Пример #10
0
Eterm
erts_msg_distext2heap(Process *pp,
                      ErtsProcLocks *plcksp,
                      ErlHeapFragment **bpp,
                      Eterm *tokenp,
                      ErtsDistExternal *dist_extp)
{
    Eterm msg;
    Uint tok_sz = 0;
    Eterm *hp = NULL;
    Eterm *hp_end = NULL;
    ErlOffHeap *ohp;
    Sint sz;

    *bpp = NULL;
    sz = erts_decode_dist_ext_size(dist_extp);
    if (sz < 0)
        goto decode_error;
    if (is_not_nil(*tokenp)) {
        ErlHeapFragment *heap_frag = erts_dist_ext_trailer(dist_extp);
        tok_sz = heap_frag->used_size;
        sz += tok_sz;
    }
    if (pp)
        hp = erts_alloc_message_heap(sz, bpp, &ohp, pp, plcksp);
    else {
        *bpp = new_message_buffer(sz);
        hp = (*bpp)->mem;
        ohp = &(*bpp)->off_heap;
    }
    hp_end = hp + sz;
    msg = erts_decode_dist_ext(&hp, ohp, dist_extp);
    if (is_non_value(msg))
        goto decode_error;
    if (is_not_nil(*tokenp)) {
        ErlHeapFragment *heap_frag = erts_dist_ext_trailer(dist_extp);
        *tokenp = copy_struct(*tokenp, tok_sz, &hp, ohp);
        erts_cleanup_offheap(&heap_frag->off_heap);
    }
    erts_free_dist_ext_copy(dist_extp);
    if (hp_end != hp) {
        if (!(*bpp)) {
            HRelease(pp, hp_end, hp);
        }
        else {
            Uint final_size = hp - &(*bpp)->mem[0];
            Eterm brefs[2] = {msg, *tokenp};
            ASSERT(sz - (hp_end - hp) == final_size);
            *bpp = erts_resize_message_buffer(*bpp, final_size, &brefs[0], 2);
            msg = brefs[0];
            *tokenp = brefs[1];
        }
    }
    return msg;

decode_error:
    if (is_not_nil(*tokenp)) {
        ErlHeapFragment *heap_frag = erts_dist_ext_trailer(dist_extp);
        erts_cleanup_offheap(&heap_frag->off_heap);
    }
    erts_free_dist_ext_copy(dist_extp);
    if (*bpp) {
        free_message_buffer(*bpp);
        *bpp = NULL;
    }
    else if (hp) {
        HRelease(pp, hp_end, hp);
    }
    return THE_NON_VALUE;
}