예제 #1
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
}
예제 #2
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
}
예제 #3
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
    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))
#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
#ifdef USE_VM_PROBES
                               , NIL
#endif
                              );
        }
        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);

            notify_new_message(rcvr);
        }
}
예제 #4
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);
    }
}