Exemple #1
0
void
erts_queue_dist_message(Process *rcvr,
			ErtsProcLocks rcvr_locks,
			ErtsDistExternal *dist_ext,
			Eterm token,
                        Eterm from)
{
    ErtsMessage* mp;
    erts_aint_t state;

    ERTS_LC_ASSERT(rcvr_locks == erts_proc_lc_my_proc_locks(rcvr));

    mp = erts_alloc_message(0, NULL);
    mp->data.dist_ext = dist_ext;

    ERL_MESSAGE_FROM(mp) = dist_ext->dep->sysname;
    ERL_MESSAGE_TERM(mp) = THE_NON_VALUE;
#ifdef USE_VM_PROBES
    ERL_MESSAGE_DT_UTAG(mp) = NIL;
    if (token == am_have_dt_utag)
	ERL_MESSAGE_TOKEN(mp) = NIL;
    else
#endif
	ERL_MESSAGE_TOKEN(mp) = token;

    if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ)) {
	if (erts_proc_trylock(rcvr, ERTS_PROC_LOCK_MSGQ) == EBUSY) {
	    ErtsProcLocks need_locks = ERTS_PROC_LOCK_MSGQ;
            ErtsProcLocks unlocks =
                rcvr_locks & ERTS_PROC_LOCKS_HIGHER_THAN(ERTS_PROC_LOCK_MSGQ);
	    if (unlocks) {
		erts_proc_unlock(rcvr, unlocks);
		need_locks |= unlocks;
	    }
	    erts_proc_lock(rcvr, need_locks);
	}
    }


    state = erts_atomic32_read_acqb(&rcvr->state);
    if (state & ERTS_PSFLG_EXITING) {
	if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ))
	    erts_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ);
	/* Drop message if receiver is exiting or has a pending exit ... */
	erts_cleanup_messages(mp);
    }
    else {
	LINK_MESSAGE(rcvr, mp);

        if (rcvr_locks & ERTS_PROC_LOCK_MAIN)
            erts_proc_sig_fetch(rcvr);

	if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ))
	    erts_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ);

	erts_proc_notify_new_message(rcvr, rcvr_locks);
    }
}
Exemple #2
0
/* Add messages last in message queue */
static Sint
queue_messages(Process* receiver,
               erts_aint32_t *receiver_state,
               ErtsProcLocks receiver_locks,
               ErtsMessage* first,
               ErtsMessage** last,
               Uint len,
               Eterm from)
{
    ErtsTracingEvent* te;
    Sint res;
    int locked_msgq = 0;
    erts_aint32_t state;

    ASSERT(is_value(ERL_MESSAGE_TERM(first)));
    ASSERT(ERL_MESSAGE_TOKEN(first) == am_undefined ||
           ERL_MESSAGE_TOKEN(first) == NIL ||
           is_tuple(ERL_MESSAGE_TOKEN(first)));

#ifdef ERTS_ENABLE_LOCK_CHECK
    ERTS_LC_ASSERT(erts_proc_lc_my_proc_locks(receiver) < ERTS_PROC_LOCK_MSGQ ||
                       receiver_locks == erts_proc_lc_my_proc_locks(receiver));
#endif

    if (!(receiver_locks & ERTS_PROC_LOCK_MSGQ)) {
	if (erts_proc_trylock(receiver, ERTS_PROC_LOCK_MSGQ) == EBUSY) {
            ErtsProcLocks need_locks;

	    if (receiver_state)
		state = *receiver_state;
	    else
		state = erts_atomic32_read_nob(&receiver->state);
	    if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT))
		goto exiting;

            need_locks = receiver_locks & ERTS_PROC_LOCKS_HIGHER_THAN(ERTS_PROC_LOCK_MSGQ);
	    if (need_locks) {
		erts_proc_unlock(receiver, need_locks);
	    }
            need_locks |= ERTS_PROC_LOCK_MSGQ;
	    erts_proc_lock(receiver, need_locks);
	}
	locked_msgq = 1;
    }


    state = erts_atomic32_read_nob(&receiver->state);

    if (state & (ERTS_PSFLG_PENDING_EXIT|ERTS_PSFLG_EXITING)) {
    exiting:
	/* Drop message if receiver is exiting or has a pending exit... */
	if (locked_msgq)
	    erts_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ);
	erts_cleanup_messages(first);
	return 0;
    }

    res = receiver->msg.len;
    if (receiver_locks & ERTS_PROC_LOCK_MAIN) {
	/*
	 * 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.
	 */
	res += receiver->msg_inq.len;
	ERTS_MSGQ_MV_INQ2PRIVQ(receiver);
        LINK_MESSAGE_PRIVQ(receiver, first, last, len);
    }
    else
    {
	LINK_MESSAGE(receiver, first, last, len);
    }

    if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)
        && (te = &erts_receive_tracing[erts_active_bp_ix()],
            te->on)) {

        ErtsMessage *msg = first;

#ifdef USE_VM_PROBES
        if (DTRACE_ENABLED(message_queued)) {
            DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE);
            Sint tok_label = 0;
            Sint tok_lastcnt = 0;
            Sint tok_serial = 0;
            Eterm seq_trace_token = ERL_MESSAGE_TOKEN(msg);

            dtrace_proc_str(receiver, receiver_name);
            if (seq_trace_token != NIL && is_tuple(seq_trace_token)) {
                tok_label = signed_val(SEQ_TRACE_T_LABEL(seq_trace_token));
                tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(seq_trace_token));
                tok_serial = signed_val(SEQ_TRACE_T_SERIAL(seq_trace_token));
            }
            DTRACE6(message_queued,
                    receiver_name, size_object(ERL_MESSAGE_TERM(msg)),
                    receiver->msg.len,
                    tok_label, tok_lastcnt, tok_serial);
        }
#endif
        while (msg) {
            trace_receive(receiver, from, ERL_MESSAGE_TERM(msg), te);
            msg = msg->next;
        }

    }
    if (locked_msgq) {
	erts_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ);
    }

    erts_proc_notify_new_message(receiver, receiver_locks);
    return res;
}
Exemple #3
0
void
erts_queue_dist_message(Process *rcvr,
			ErtsProcLocks rcvr_locks,
			ErtsDistExternal *dist_ext,
			Eterm token,
                        Eterm from)
{
    ErtsMessage* mp;
#ifdef USE_VM_PROBES
    Sint tok_label = 0;
    Sint tok_lastcnt = 0;
    Sint tok_serial = 0;
#endif
    erts_aint_t state;

    ERTS_LC_ASSERT(rcvr_locks == erts_proc_lc_my_proc_locks(rcvr));

    mp = erts_alloc_message(0, NULL);
    mp->data.dist_ext = dist_ext;

    ERL_MESSAGE_TERM(mp) = THE_NON_VALUE;
#ifdef USE_VM_PROBES
    ERL_MESSAGE_DT_UTAG(mp) = NIL;
    if (token == am_have_dt_utag)
	ERL_MESSAGE_TOKEN(mp) = NIL;
    else
#endif
	ERL_MESSAGE_TOKEN(mp) = token;

    if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ)) {
	if (erts_proc_trylock(rcvr, ERTS_PROC_LOCK_MSGQ) == EBUSY) {
	    ErtsProcLocks need_locks = ERTS_PROC_LOCK_MSGQ;
            ErtsProcLocks unlocks =
                rcvr_locks & ERTS_PROC_LOCKS_HIGHER_THAN(ERTS_PROC_LOCK_MSGQ);
	    if (unlocks) {
		erts_proc_unlock(rcvr, unlocks);
		need_locks |= unlocks;
	    }
	    erts_proc_lock(rcvr, need_locks);
	}
    }

    state = erts_atomic32_read_acqb(&rcvr->state);
    if (state & (ERTS_PSFLG_PENDING_EXIT|ERTS_PSFLG_EXITING)) {
	if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ))
	    erts_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ);
	/* Drop message if receiver is exiting or has a pending exit ... */
	erts_cleanup_messages(mp);
    }
    else
    if (IS_TRACED_FL(rcvr, F_TRACE_RECEIVE)) {
        if (from == am_Empty)
            from = dist_ext->dep->sysname;

	/* Ahh... need to decode it in order to trace it... */
	if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ))
	    erts_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ);
	if (!erts_decode_dist_message(rcvr, rcvr_locks, mp, 0))
	    erts_free_message(mp);
	else {
	    Eterm msg = ERL_MESSAGE_TERM(mp);
	    token = ERL_MESSAGE_TOKEN(mp);
#ifdef USE_VM_PROBES
	    if (DTRACE_ENABLED(message_queued)) {
		DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE);

		dtrace_proc_str(rcvr, receiver_name);
                if (have_seqtrace(token)) {
		    tok_label = signed_val(SEQ_TRACE_T_LABEL(token));
		    tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token));
		    tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token));
		}
		DTRACE6(message_queued,
			receiver_name, size_object(msg), rcvr->msg.len,
			tok_label, tok_lastcnt, tok_serial);
	    }
#endif
	    erts_queue_message(rcvr, rcvr_locks, mp, msg, from);
	}
    }
    else {
	/* Enqueue message on external format */

#ifdef USE_VM_PROBES
        if (DTRACE_ENABLED(message_queued)) {
            DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE);

            dtrace_proc_str(rcvr, receiver_name);
            if (have_seqtrace(token)) {
                tok_label = signed_val(SEQ_TRACE_T_LABEL(token));
                tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token));
                tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token));
            }
            /*
             * TODO: We don't know the real size of the external message here.
             *       -1 will appear to a D script as 4294967295.
             */
            DTRACE6(message_queued, receiver_name, -1, rcvr->msg.len + 1,
                    tok_label, tok_lastcnt, tok_serial);
        }
#endif

	LINK_MESSAGE(rcvr, mp, &mp->next, 1);

	if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ))
	    erts_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ);

	erts_proc_notify_new_message(rcvr,
				     rcvr_locks
	    );
    }
}
Exemple #4
0
/* Add a message last in message queue */
static Sint
queue_message(Process *c_p,
	      Process* receiver,
	      erts_aint32_t *receiver_state,
	      ErtsProcLocks *receiver_locks,
	      ErtsMessage* mp,
	      Eterm message,
	      Eterm seq_trace_token
#ifdef USE_VM_PROBES
		   , Eterm dt_utag
#endif
    )
{
    Sint res;
    int locked_msgq = 0;
    erts_aint32_t state;

    ERTS_SMP_LC_ASSERT(*receiver_locks == erts_proc_lc_my_proc_locks(receiver));

#ifdef ERTS_SMP

    if (!(*receiver_locks & ERTS_PROC_LOCK_MSGQ)) {
	if (erts_smp_proc_trylock(receiver, ERTS_PROC_LOCK_MSGQ) == EBUSY) {
	    ErtsProcLocks need_locks = ERTS_PROC_LOCK_MSGQ;

	    if (receiver_state)
		state = *receiver_state;
	    else
		state = erts_smp_atomic32_read_nob(&receiver->state);
	    if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT))
		goto exiting;

	    if (*receiver_locks & ERTS_PROC_LOCK_STATUS) {
		erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_STATUS);
		need_locks |= ERTS_PROC_LOCK_STATUS;
	    }
	    erts_smp_proc_lock(receiver, need_locks);
	}
	locked_msgq = 1;
    }

#endif

    state = erts_smp_atomic32_read_nob(&receiver->state);

    if (state & (ERTS_PSFLG_PENDING_EXIT|ERTS_PSFLG_EXITING)) {
#ifdef ERTS_SMP
    exiting:
#endif
	/* Drop message if receiver is exiting or has a pending exit... */
	if (locked_msgq)
	    erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ);
	erts_cleanup_messages(mp);
	return 0;
    }

    ERL_MESSAGE_TERM(mp) = message;
    ERL_MESSAGE_TOKEN(mp) = seq_trace_token;
#ifdef USE_VM_PROBES
    ERL_MESSAGE_DT_UTAG(mp) = dt_utag;
#endif

    res = receiver->msg.len;
#ifdef ERTS_SMP
    if (*receiver_locks & ERTS_PROC_LOCK_MAIN) {
	/*
	 * 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.
	 */
	res += receiver->msg_inq.len;
	ERTS_SMP_MSGQ_MV_INQ2PRIVQ(receiver);
	LINK_MESSAGE_PRIVQ(receiver, mp);
    }
    else
#endif
    {
	LINK_MESSAGE(receiver, mp);
    }

#ifdef USE_VM_PROBES
    if (DTRACE_ENABLED(message_queued)) {
        DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE);
        Sint tok_label = 0;
        Sint tok_lastcnt = 0;
        Sint tok_serial = 0;

        dtrace_proc_str(receiver, receiver_name);
        if (seq_trace_token != NIL && is_tuple(seq_trace_token)) {
            tok_label = signed_val(SEQ_TRACE_T_LABEL(seq_trace_token));
            tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(seq_trace_token));
            tok_serial = signed_val(SEQ_TRACE_T_SERIAL(seq_trace_token));
        }
        DTRACE6(message_queued,
                receiver_name, size_object(message), receiver->msg.len,
                tok_label, tok_lastcnt, tok_serial);
    }
#endif

    if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE))
	trace_receive(receiver, message);

    if (locked_msgq)
	erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ);

    erts_proc_notify_new_message(receiver,
#ifdef ERTS_SMP
				 *receiver_locks
#else
				 0
#endif
	);

#ifndef ERTS_SMP
    ERTS_HOLE_CHECK(receiver);
#endif
    return res;
}
Exemple #5
0
void
erts_queue_dist_message(Process *rcvr,
			ErtsProcLocks *rcvr_locks,
			ErtsDistExternal *dist_ext,
			Eterm token)
{
    ErlMessage* mp;
#ifdef USE_VM_PROBES
    Sint tok_label = 0;
    Sint tok_lastcnt = 0;
    Sint tok_serial = 0;
#endif
#ifdef ERTS_SMP
    erts_aint_t state;
#endif

    ERTS_SMP_LC_ASSERT(*rcvr_locks == erts_proc_lc_my_proc_locks(rcvr));

    mp = message_alloc();

#ifdef ERTS_SMP
    if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ)) {
	if (erts_smp_proc_trylock(rcvr, ERTS_PROC_LOCK_MSGQ) == EBUSY) {
	    ErtsProcLocks need_locks = ERTS_PROC_LOCK_MSGQ;
	    if (*rcvr_locks & ERTS_PROC_LOCK_STATUS) {
		erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_STATUS);
		need_locks |= ERTS_PROC_LOCK_STATUS;
	    }
	    erts_smp_proc_lock(rcvr, need_locks);
	}
    }

    state = erts_smp_atomic32_read_acqb(&rcvr->state);
    if (state & (ERTS_PSFLG_PENDING_EXIT|ERTS_PSFLG_EXITING)) {
	if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ))
	    erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ);
	/* Drop message if receiver is exiting or has a pending exit ... */
	if (is_not_nil(token)) {
	    ErlHeapFragment *heap_frag;
	    heap_frag = erts_dist_ext_trailer(mp->data.dist_ext);
	    erts_cleanup_offheap(&heap_frag->off_heap);
	}
	erts_free_dist_ext_copy(dist_ext);
	message_free(mp);
    }
    else
#endif
    if (IS_TRACED_FL(rcvr, F_TRACE_RECEIVE)) {
	/* Ahh... need to decode it in order to trace it... */
	ErlHeapFragment *mbuf;
	Eterm msg;
	if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ))
	    erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ);
	message_free(mp);
	msg = erts_msg_distext2heap(rcvr, rcvr_locks, &mbuf, &token, dist_ext);
	if (is_value(msg))
#ifdef USE_VM_PROBES
            if (DTRACE_ENABLED(message_queued)) {
                DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE);

                dtrace_proc_str(rcvr, receiver_name);
                if (token != NIL && token != am_have_dt_utag) {
                    tok_label = signed_val(SEQ_TRACE_T_LABEL(token));
                    tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token));
                    tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token));
                }
                DTRACE6(message_queued,
                        receiver_name, size_object(msg), rcvr->msg.len,
                        tok_label, tok_lastcnt, tok_serial);
            }
#endif
	    erts_queue_message(rcvr, rcvr_locks, mbuf, msg, token);
    }
    else {
	/* Enqueue message on external format */

	ERL_MESSAGE_TERM(mp) = THE_NON_VALUE;
#ifdef USE_VM_PROBES
	ERL_MESSAGE_DT_UTAG(mp) = NIL;
	if (token == am_have_dt_utag) {
	    ERL_MESSAGE_TOKEN(mp) = NIL;
	} else {
#endif
	    ERL_MESSAGE_TOKEN(mp) = token;
#ifdef USE_VM_PROBES
	}
#endif
	mp->next = NULL;

#ifdef USE_VM_PROBES
        if (DTRACE_ENABLED(message_queued)) {
            DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE);

            dtrace_proc_str(rcvr, receiver_name);
            if (token != NIL && token != am_have_dt_utag) {
                tok_label = signed_val(SEQ_TRACE_T_LABEL(token));
                tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token));
                tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token));
            }
            /*
             * TODO: We don't know the real size of the external message here.
             *       -1 will appear to a D script as 4294967295.
             */
            DTRACE6(message_queued, receiver_name, -1, rcvr->msg.len + 1,
                    tok_label, tok_lastcnt, tok_serial);
        }
#endif
	mp->data.dist_ext = dist_ext;
	LINK_MESSAGE(rcvr, mp);

	if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ))
	    erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ);

	erts_proc_notify_new_message(rcvr,
#ifdef ERTS_SMP
				     *rcvr_locks
#else
				     0
#endif
	    );
    }
}
Exemple #6
0
/* Add messages last in message queue */
static void
queue_messages(Process* receiver,
               ErtsProcLocks receiver_locks,
               ErtsMessage* first,
               ErtsMessage** last,
               Uint len)
{
    int locked_msgq = 0;
    erts_aint32_t state;

#ifdef DEBUG
    {
        ErtsMessage* fmsg = ERTS_SIG_IS_MSG(first) ? first : first->next;
        ASSERT(fmsg);
        ASSERT(is_value(ERL_MESSAGE_TERM(fmsg)));
        ASSERT(is_value(ERL_MESSAGE_FROM(fmsg)));
        ASSERT(ERL_MESSAGE_TOKEN(fmsg) == am_undefined ||
               ERL_MESSAGE_TOKEN(fmsg) == NIL ||
               is_tuple(ERL_MESSAGE_TOKEN(fmsg)));
    }
#endif

    ERTS_LC_ASSERT((erts_proc_lc_my_proc_locks(receiver) & ERTS_PROC_LOCK_MSGQ)
                   == (receiver_locks & ERTS_PROC_LOCK_MSGQ));

    if (!(receiver_locks & ERTS_PROC_LOCK_MSGQ)) {
        erts_proc_lock(receiver, ERTS_PROC_LOCK_MSGQ);
	locked_msgq = 1;
    }

    state = erts_atomic32_read_nob(&receiver->state);

    if (state & ERTS_PSFLG_EXITING) {
	/* Drop message if receiver is exiting or has a pending exit... */
	if (locked_msgq)
            erts_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ);
        if (ERTS_SIG_IS_NON_MSG(first)) {
            ErtsSchedulerData* esdp = erts_get_scheduler_data();
            ASSERT(esdp);
            ASSERT(!esdp->pending_signal.sig);
            esdp->pending_signal.sig = (ErtsSignal*) first;
            esdp->pending_signal.to = receiver->common.id;
            first = first->next;
        }
	erts_cleanup_messages(first);
        return;
    }

    if (last == &first->next) {
        ASSERT(len == 1);
        LINK_MESSAGE(receiver, first);
    }
    else {
        erts_enqueue_signals(receiver, first, last, NULL, len, state);
    }

    if (receiver_locks & ERTS_PROC_LOCK_MAIN)
        erts_proc_sig_fetch(receiver);

    if (locked_msgq) {
	erts_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ);
    }

    if (last == &first->next)
        erts_proc_notify_new_message(receiver, receiver_locks);
    else
        erts_proc_notify_new_sig(receiver, state, ERTS_PSFLG_ACTIVE);
}
Exemple #7
0
void
erts_queue_dist_message(Process *rcvr,
			ErtsProcLocks rcvr_locks,
			ErtsDistExternal *dist_ext,
                        ErlHeapFragment *hfrag,
			Eterm token,
                        Eterm from)
{
    ErtsMessage* mp;
    erts_aint_t state;

    ERTS_LC_ASSERT(rcvr_locks == erts_proc_lc_my_proc_locks(rcvr));

    if (hfrag) {
        /* Fragmented message, allocate a message reference */
        mp = erts_alloc_message(0, NULL);
        mp->data.heap_frag = hfrag;
    } else {
        /* Un-fragmented message, allocate space for
           token and dist_ext in message. */
        Uint dist_ext_sz = erts_dist_ext_size(dist_ext) / sizeof(Eterm);
        Uint token_sz = size_object(token);
        Uint sz = token_sz + dist_ext_sz;
        Eterm *hp;

        mp = erts_alloc_message(sz, &hp);
        mp->data.heap_frag = &mp->hfrag;
        mp->hfrag.used_size = token_sz;

        erts_make_dist_ext_copy(dist_ext, erts_get_dist_ext(mp->data.heap_frag));

        token = copy_struct(token, token_sz, &hp, &mp->data.heap_frag->off_heap);
    }

    ERL_MESSAGE_FROM(mp) = dist_ext->dep->sysname;
    ERL_MESSAGE_TERM(mp) = THE_NON_VALUE;
#ifdef USE_VM_PROBES
    ERL_MESSAGE_DT_UTAG(mp) = NIL;
    if (token == am_have_dt_utag)
	ERL_MESSAGE_TOKEN(mp) = NIL;
    else
#endif
	ERL_MESSAGE_TOKEN(mp) = token;

    if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ)) {
	if (erts_proc_trylock(rcvr, ERTS_PROC_LOCK_MSGQ) == EBUSY) {
	    ErtsProcLocks need_locks = ERTS_PROC_LOCK_MSGQ;
            ErtsProcLocks unlocks =
                rcvr_locks & ERTS_PROC_LOCKS_HIGHER_THAN(ERTS_PROC_LOCK_MSGQ);
	    if (unlocks) {
		erts_proc_unlock(rcvr, unlocks);
		need_locks |= unlocks;
	    }
	    erts_proc_lock(rcvr, need_locks);
	}
    }


    state = erts_atomic32_read_acqb(&rcvr->state);
    if (state & ERTS_PSFLG_EXITING) {
	if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ))
	    erts_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ);
	/* Drop message if receiver is exiting or has a pending exit ... */
	erts_cleanup_messages(mp);
    }
    else {
	LINK_MESSAGE(rcvr, mp);

        if (rcvr_locks & ERTS_PROC_LOCK_MAIN)
            erts_proc_sig_fetch(rcvr);

	if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ))
	    erts_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ);

	erts_proc_notify_new_message(rcvr, rcvr_locks);
    }
}
Exemple #8
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;
    }
}
Exemple #9
0
/* Add a message last in message queue */
void
erts_queue_message(Process* receiver,
                   ErtsProcLocks *receiver_locks,
                   ErlHeapFragment* bp,
                   Eterm message,
                   Eterm seq_trace_token
#ifdef USE_VM_PROBES
                   , Eterm dt_utag
#endif
                  )
{
    ErlMessage* mp;
#ifdef ERTS_SMP
    ErtsProcLocks need_locks;
#else
    ASSERT(bp != NULL || receiver->mbuf == NULL);
#endif

    ERTS_SMP_LC_ASSERT(*receiver_locks == erts_proc_lc_my_proc_locks(receiver));

    mp = message_alloc();

#ifdef ERTS_SMP
    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 (receiver->is_exiting || ERTS_PROC_PENDING_EXIT(receiver)) {
        /* Drop message if receiver is exiting or has a pending
         * exit ...
         */
        if (bp)
            free_message_buffer(bp);
        message_free(mp);
        return;
    }
#endif

    ERL_MESSAGE_TERM(mp) = message;
    ERL_MESSAGE_TOKEN(mp) = seq_trace_token;
#ifdef USE_VM_PROBES
    ERL_MESSAGE_DT_UTAG(mp) = dt_utag;
#endif
    mp->next = NULL;
    mp->data.heap_frag = bp;

#ifdef ERTS_SMP
    if (*receiver_locks & ERTS_PROC_LOCK_MAIN) {
        /*
         * 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);
    }
    else {
        LINK_MESSAGE(receiver, mp);
    }
#else
    LINK_MESSAGE(receiver, mp);
#endif

#ifdef USE_VM_PROBES
    if (DTRACE_ENABLED(message_queued)) {
        DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE);
        Sint tok_label = 0;
        Sint tok_lastcnt = 0;
        Sint tok_serial = 0;

        dtrace_proc_str(receiver, receiver_name);
        if (seq_trace_token != NIL && is_tuple(seq_trace_token)) {
            tok_label = signed_val(SEQ_TRACE_T_LABEL(seq_trace_token));
            tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(seq_trace_token));
            tok_serial = signed_val(SEQ_TRACE_T_SERIAL(seq_trace_token));
        }
        DTRACE6(message_queued,
                receiver_name, size_object(message), receiver->msg.len,
                tok_label, tok_lastcnt, tok_serial);
    }
#endif
    notify_new_message(receiver);

    if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)) {
        trace_receive(receiver, message);
    }

#ifndef ERTS_SMP
    ERTS_HOLE_CHECK(receiver);
#endif
}
Exemple #10
0
//将消息放入目标进程的消息队列中
static Sint
queue_message(Process *c_p,
			  Process* receiver,
			  ErtsProcLocks *receiver_locks,
			  erts_aint32_t *receiver_state,
			  ErlHeapFragment* bp,
			  Eterm message,
			  Eterm seq_trace_token
#ifdef USE_VM_PROBES
		   , Eterm dt_utag
#endif
    )
{
    Sint res;
    ErlMessage* mp;
    int locked_msgq = 0;
    erts_aint_t state;

#ifndef ERTS_SMP
    ASSERT(bp != NULL || receiver->mbuf == NULL);
#endif

    ERTS_SMP_LC_ASSERT(*receiver_locks == erts_proc_lc_my_proc_locks(receiver));

    mp = message_alloc();

    if (receiver_state){
		 state = *receiver_state;
	}else{
		 state = erts_smp_atomic32_read_acqb(&receiver->state);
	}

#ifdef ERTS_SMP
//如果目标进程处在退出的状态,直接进入退出清理
    if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT)){
		 goto exiting;
	}
//如果当前没有目标Erlang进程的消息队列锁
//尝试获取消息队列的锁
    if (!(*receiver_locks & ERTS_PROC_LOCK_MSGQ)) {
		 if (erts_smp_proc_trylock(receiver, ERTS_PROC_LOCK_MSGQ) == EBUSY) {
			  ErtsProcLocks need_locks = ERTS_PROC_LOCK_MSGQ;
			  if (*receiver_locks & ERTS_PROC_LOCK_STATUS) {
				   erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_STATUS);
				   need_locks |= ERTS_PROC_LOCK_STATUS;
			  }
			  erts_smp_proc_lock(receiver, need_locks);
		 }
		 locked_msgq = 1;
		 state = erts_smp_atomic32_read_nob(&receiver->state);
//获取目标Erlang进程的状态
		 if (receiver_state){
			  *receiver_state = state;
		 }
    }

#endif
//Erlang进程处于退出的状态
//直接释放目标进程的锁,和当前消息
    if (state & (ERTS_PSFLG_PENDING_EXIT|ERTS_PSFLG_EXITING)) {
#ifdef ERTS_SMP
    exiting:
#endif
	/* Drop message if receiver is exiting or has a pending exit... */
		 if (locked_msgq){
			  erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ);
		 }
		 if (bp){
			  free_message_buffer(bp);
		 }
		 message_free(mp);
		 return 0;
    }
//从此处可以看出,放入目标进程的消息,只是对当前进程的消息的一个指针应用
//那我们需要找出,message是如何被处理的,何时增加的引用计数
    ERL_MESSAGE_TERM(mp) = message;
    ERL_MESSAGE_TOKEN(mp) = seq_trace_token;
#ifdef USE_VM_PROBES
    ERL_MESSAGE_DT_UTAG(mp) = dt_utag;
#endif
    mp->next = NULL;
    mp->data.heap_frag = bp;

#ifndef ERTS_SMP
    res = receiver->msg.len;
#else
    res = receiver->msg_inq.len;
//把消息attach的目标Erlang进程的消息队列或者private
//的消息队列
    if (*receiver_locks & ERTS_PROC_LOCK_MAIN) {
	/*
	 * 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.
	 */
//这个时候可以操作msg_inq和msg
		 res += receiver->msg.len;
		 ERTS_SMP_MSGQ_MV_INQ2PRIVQ(receiver);
		 LINK_MESSAGE_PRIVQ(receiver, mp);
    }
    else
#endif
    {
//这个时候只操作msg_inq
		 LINK_MESSAGE(receiver, mp);
    }

#ifdef USE_VM_PROBES
    if (DTRACE_ENABLED(message_queued)) {
        DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE);
        Sint tok_label = 0;
        Sint tok_lastcnt = 0;
        Sint tok_serial = 0;

        dtrace_proc_str(receiver, receiver_name);
        if (seq_trace_token != NIL && is_tuple(seq_trace_token)) {
            tok_label = signed_val(SEQ_TRACE_T_LABEL(seq_trace_token));
            tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(seq_trace_token));
            tok_serial = signed_val(SEQ_TRACE_T_SERIAL(seq_trace_token));
        }
        DTRACE6(message_queued,
                receiver_name, size_object(message), receiver->msg.len,
                tok_label, tok_lastcnt, tok_serial);
    }
#endif

    if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)){
		 trace_receive(receiver, message);
	}

    if (locked_msgq){
		 erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ);
	}
    erts_proc_notify_new_message(receiver,
#ifdef ERTS_SMP
				 *receiver_locks
#else
				 0
#endif
	);

#ifndef ERTS_SMP
    ERTS_HOLE_CHECK(receiver);
#endif
    return res;
}
Exemple #11
0
void
erts_send_message(Process* sender,
		  Process* receiver,
		  ErtsProcLocks *receiver_locks,
		  Eterm message,
		  unsigned flags)
{
    Uint msize;
    ErlHeapFragment* bp = NULL;
    Eterm token = NIL;

    BM_STOP_TIMER(system);
    BM_MESSAGE(message,sender,receiver);
    BM_START_TIMER(send);

    if (SEQ_TRACE_TOKEN(sender) != NIL && !(flags & ERTS_SND_FLG_NO_SEQ_TRACE)) {
        Eterm* hp;

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

	seq_trace_update_send(sender);
	seq_trace_output(SEQ_TRACE_TOKEN(sender), message, SEQ_TRACE_SEND, 
			 receiver->id, sender);
	bp = new_message_buffer(msize + 6 /* TUPLE5 */);
	hp = bp->mem;

        BM_SWAP_TIMER(send,copy);
	token = copy_struct(SEQ_TRACE_TOKEN(sender),
			    6 /* TUPLE5 */,
			    &hp,
			    &bp->off_heap);

	message = copy_struct(message, msize, &hp, &bp->off_heap);
        BM_MESSAGE_COPIED(msize);
        BM_SWAP_TIMER(copy,send);

        erts_queue_message(receiver,
			   receiver_locks,
			   bp,
			   message,
			   token);
        BM_SWAP_TIMER(send,system);
#ifdef HYBRID
    } else {
        ErlMessage* mp = message_alloc();
        BM_SWAP_TIMER(send,copy);
#ifdef INCREMENTAL
        /* TODO: During GC activate processes if the message relies in
         * the fromspace and the sender is active. During major
         * collections add the message to the gray stack if it relies
         * in the old generation and the sender is active and the
         * receiver is inactive.

        if (!IS_CONST(message) && (ma_gc_flags & GC_CYCLE) &&
            (ptr_val(message) >= inc_fromspc &&
            ptr_val(message) < inc_fromend) && INC_IS_ACTIVE(sender))
            INC_ACTIVATE(receiver);
        else if (!IS_CONST(message) && (ma_gc_flags & GC_CYCLE) &&
            (ptr_val(message) >= global_old_heap &&
            ptr_val(message) < global_old_hend) &&
            INC_IS_ACTIVE(sender) && !INC_IS_ACTIVE(receiver))
            Mark message in blackmap and add it to the gray stack
        */

         if (!IS_CONST(message))
            INC_ACTIVATE(receiver);
#endif
        LAZY_COPY(sender,message);
        BM_SWAP_TIMER(copy,send);
        ERL_MESSAGE_TERM(mp) = message;
        ERL_MESSAGE_TOKEN(mp) = NIL;
        mp->next = NULL;
	LINK_MESSAGE(receiver, mp);
        ACTIVATE(receiver);

        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);
        return;
#else
    } else if (sender == receiver) {
Exemple #12
0
/* Add a message last in message queue */
void
erts_queue_message(Process* receiver,
		   ErtsProcLocks *receiver_locks,
		   ErlHeapFragment* bp,
		   Eterm message,
		   Eterm seq_trace_token)
{
    ErlMessage* mp;
#ifdef ERTS_SMP
    ErtsProcLocks need_locks;
#else
    ASSERT(bp != NULL || receiver->mbuf == NULL);
#endif

    ERTS_SMP_LC_ASSERT(*receiver_locks == erts_proc_lc_my_proc_locks(receiver));

    mp = message_alloc();

#ifdef ERTS_SMP
    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 (receiver->is_exiting || ERTS_PROC_PENDING_EXIT(receiver)) {
	/* Drop message if receiver is exiting or has a pending
	 * exit ...
	 */
	if (bp)
	    free_message_buffer(bp);
	message_free(mp);
	return;
    }
#endif

    ERL_MESSAGE_TERM(mp) = message;
    ERL_MESSAGE_TOKEN(mp) = seq_trace_token;
    mp->next = NULL;

#ifdef ERTS_SMP
    if (*receiver_locks & ERTS_PROC_LOCK_MAIN) {
	mp->data.heap_frag = bp;

	/*
	 * 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);
    }
    else {
	mp->data.heap_frag = bp;
	LINK_MESSAGE(receiver, mp);
    }
#else
    mp->data.heap_frag = bp;
    LINK_MESSAGE(receiver, mp);
#endif

    notify_new_message(receiver);

    if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)) {
	trace_receive(receiver, message);
    }
    
#ifndef ERTS_SMP
    ERTS_HOLE_CHECK(receiver);
#endif
}
Exemple #13
0
void
erts_queue_dist_message(Process *rcvr,
			ErtsProcLocks *rcvr_locks,
			ErtsDistExternal *dist_ext,
			Eterm token)
{
    ErlMessage* mp;
#ifdef ERTS_SMP
    ErtsProcLocks need_locks;
#endif

    ERTS_SMP_LC_ASSERT(*rcvr_locks == erts_proc_lc_my_proc_locks(rcvr));

    mp = message_alloc();

#ifdef ERTS_SMP
    need_locks = ~(*rcvr_locks) & (ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS);
    if (need_locks) {
	*rcvr_locks |= need_locks;
	if (erts_smp_proc_trylock(rcvr, need_locks) == EBUSY) {
	    if (need_locks == ERTS_PROC_LOCK_MSGQ) {
		erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_STATUS);
		need_locks = (ERTS_PROC_LOCK_MSGQ
			      | ERTS_PROC_LOCK_STATUS);
	    }
	    erts_smp_proc_lock(rcvr, need_locks);
	}
    }

    if (rcvr->is_exiting || ERTS_PROC_PENDING_EXIT(rcvr)) {
	/* Drop message if receiver is exiting or has a pending exit ... */
	if (is_not_nil(token)) {
	    ErlHeapFragment *heap_frag;
	    heap_frag = erts_dist_ext_trailer(mp->data.dist_ext);
	    erts_cleanup_offheap(&heap_frag->off_heap);
	}
	erts_free_dist_ext_copy(dist_ext);
	message_free(mp);
    }
    else
#endif
    if (IS_TRACED_FL(rcvr, F_TRACE_RECEIVE)) {
	/* Ahh... need to decode it in order to trace it... */
	ErlHeapFragment *mbuf;
	Eterm msg;
	message_free(mp);
	msg = erts_msg_distext2heap(rcvr, rcvr_locks, &mbuf, &token, dist_ext);
	if (is_value(msg))
	    erts_queue_message(rcvr, rcvr_locks, mbuf, msg, token);
    }
    else {
	/* Enqueue message on external format */

	ERL_MESSAGE_TERM(mp) = THE_NON_VALUE;
	ERL_MESSAGE_TOKEN(mp) = token;
	mp->next = NULL;

	mp->data.dist_ext = dist_ext;
	LINK_MESSAGE(rcvr, mp);

	notify_new_message(rcvr);
    }
}