1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 1997-2020. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 #ifndef __ERL_MESSAGE_H__
22 #define __ERL_MESSAGE_H__
23 
24 #include "sys.h"
25 #include "erl_vm.h"
26 #define ERTS_PROC_SIG_QUEUE_TYPE_ONLY
27 #include "erl_proc_sig_queue.h"
28 #undef ERTS_PROC_SIG_QUEUE_TYPE_ONLY
29 
30 #ifdef DEBUG
31 #define ERTS_MSG_COPY_WORDS_PER_REDUCTION 4
32 #else
33 #define ERTS_MSG_COPY_WORDS_PER_REDUCTION 64
34 #endif
35 
36 struct proc_bin;
37 struct external_thing_;
38 
39 typedef struct erl_mesg ErtsMessage;
40 
41 /*
42  * This struct represents data that must be updated by structure copy,
43  * but is stored outside of any heap.
44  */
45 
46 struct erl_off_heap_header {
47     Eterm thing_word;
48     Uint size;
49     struct erl_off_heap_header* next;
50 };
51 
52 #define OH_OVERHEAD(oh, size) do { \
53     (oh)->overhead += size;        \
54 } while(0)
55 
56 typedef struct erl_off_heap {
57     struct erl_off_heap_header* first;
58     Uint64 overhead;     /* Administrative overhead (used to force GC). */
59 } ErlOffHeap;
60 
61 #define ERTS_INIT_OFF_HEAP(OHP)			\
62     do {					\
63 	(OHP)->first = NULL;			\
64 	(OHP)->overhead = 0;			\
65     } while (0)
66 
67 typedef struct {
68     enum {
69         FACTORY_CLOSED = 0,
70         FACTORY_HALLOC,
71         FACTORY_MESSAGE,
72         FACTORY_HEAP_FRAGS,
73         FACTORY_STATIC,
74         FACTORY_TMP
75     } mode;
76     Process* p;
77     /*
78        If the factory is initialized with erts_factory_proc_prealloc_init,
79        hp_start points to the top of the main heap if the preallocated data
80        fits in the main heap and otherwise it points to somewhere in the
81        data area of a heap fragment. If the factory is initialized with any
82        of the other init functions that sets the mode to FACTORY_HALLOC,
83        hp_start and original_htop always have the same value.
84 
85        When erts_factory_proc_prealloc_init is used for initialization the
86        preallocated data might be allocated in an existing heap fragment but
87        data that is later allocated with erts_produce_heap might fit in the
88        main heap, so both hp_start and original_htop are needed to correctly
89        restore the heap in the erts_factory_undo function.
90     */
91     Eterm* hp_start;
92     /*
93        original_htop stores the top of the main heap at the time
94        the factory was initialized and is used to reset the heap
95        state if an erts_factory_undo call is made.
96     */
97     Eterm* original_htop;
98     Eterm* hp;
99     Eterm* hp_end;
100     ErtsMessage *message;
101     struct erl_heap_fragment* heap_frags;
102     struct erl_heap_fragment* heap_frags_saved;
103     Uint heap_frags_saved_used;
104     ErlOffHeap* off_heap;
105     ErlOffHeap off_heap_saved;
106     Uint32 alloc_type;
107 } ErtsHeapFactory;
108 
109 void erts_factory_proc_init(ErtsHeapFactory*, Process*);
110 void erts_factory_proc_prealloc_init(ErtsHeapFactory*, Process*, Sint size);
111 void erts_factory_heap_frag_init(ErtsHeapFactory*, struct erl_heap_fragment*);
112 ErtsMessage *erts_factory_message_create(ErtsHeapFactory *, Process *,
113 					  ErtsProcLocks *, Uint sz);
114 void erts_factory_selfcontained_message_init(ErtsHeapFactory*, ErtsMessage *, Eterm *);
115 void erts_factory_static_init(ErtsHeapFactory*, Eterm* hp, Uint size, ErlOffHeap*);
116 void erts_factory_tmp_init(ErtsHeapFactory*, Eterm* hp, Uint size, Uint32 atype);
117 void erts_factory_dummy_init(ErtsHeapFactory*);
118 
119 ERTS_GLB_INLINE Eterm* erts_produce_heap(ErtsHeapFactory*, Uint need, Uint xtra);
120 
121 Eterm* erts_reserve_heap(ErtsHeapFactory*, Uint need);
122 void erts_factory_close(ErtsHeapFactory*);
123 void erts_factory_trim_and_close(ErtsHeapFactory*,Eterm *brefs, Uint brefs_size);
124 void erts_factory_undo(ErtsHeapFactory*);
125 
126 void erts_reserve_heap__(ErtsHeapFactory*, Uint need, Uint xtra); /* internal */
127 
128 #if ERTS_GLB_INLINE_INCL_FUNC_DEF
129 
130 ERTS_GLB_INLINE Eterm *
erts_produce_heap(ErtsHeapFactory * factory,Uint need,Uint xtra)131 erts_produce_heap(ErtsHeapFactory* factory, Uint need, Uint xtra)
132 {
133     Eterm* res;
134 
135     ASSERT((unsigned int)factory->mode > (unsigned int)FACTORY_CLOSED);
136     if (factory->hp + need > factory->hp_end) {
137 	erts_reserve_heap__(factory, need, xtra);
138     }
139     res = factory->hp;
140     factory->hp += need;
141     INIT_HEAP_MEM(res, need);
142     return res;
143 }
144 
145 #endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */
146 
147 #ifdef CHECK_FOR_HOLES
148 # define ERTS_FACTORY_HOLE_CHECK(f) do {    \
149         /*if ((f)->p) erts_check_for_holes((f)->p);*/ \
150     } while (0)
151 #else
152 # define ERTS_FACTORY_HOLE_CHECK(p)
153 #endif
154 
155 #include "external.h"
156 #include "erl_process.h"
157 
158 #define ERTS_INVALID_HFRAG_PTR ((ErlHeapFragment *) ~((UWord) 7))
159 
160 /*
161  * This struct represents a heap fragment, which is used when there
162  * isn't sufficient room in the process heap and we can't do a GC.
163  */
164 
165 typedef struct erl_heap_fragment ErlHeapFragment;
166 struct erl_heap_fragment {
167     ErlHeapFragment* next;	/* Next heap fragment */
168     ErlOffHeap off_heap;	/* Offset heap data. */
169     Uint alloc_size;		/* Size in words of mem */
170     Uint used_size;		/* With terms to be moved to heap by GC */
171     Eterm mem[1];		/* Data */
172 };
173 
174 /* m[0] = message, m[1] = seq trace token */
175 #define ERL_MESSAGE_REF_ARRAY_SZ 3
176 #define ERL_MESSAGE_TERM(mp) ((mp)->m[0])
177 #define ERL_MESSAGE_TOKEN(mp) ((mp)->m[1])
178 #define ERL_MESSAGE_FROM(mp) ((mp)->m[2])
179 
180 #ifdef USE_VM_PROBES
181 /* m[2] = dynamic trace user tag */
182 #undef ERL_MESSAGE_REF_ARRAY_SZ
183 #define ERL_MESSAGE_REF_ARRAY_SZ 4
184 #define ERL_MESSAGE_DT_UTAG(mp) ((mp)->m[3])
185 #else
186 #endif
187 
188 #ifdef USE_VM_PROBES
189 #define have_no_seqtrace(T) ((T) == NIL || (T) == am_have_dt_utag)
190 #else
191 #define have_no_seqtrace(T) ((T) == NIL)
192 #endif
193 #define have_seqtrace(T)    (!have_no_seqtrace(T))
194 
195 #define ERL_MESSAGE_REF_FIELDS__			\
196     ErtsMessage *next;	/* Next message */		\
197     union {						\
198 	ErlHeapFragment *heap_frag;			\
199 	void *attached;					\
200     } data;						\
201     Eterm m[ERL_MESSAGE_REF_ARRAY_SZ]
202 
203 
204 typedef struct erl_msg_ref__ {
205     ERL_MESSAGE_REF_FIELDS__;
206 } ErtsMessageRef;
207 
208 struct erl_mesg {
209     ERL_MESSAGE_REF_FIELDS__;
210 
211     ErlHeapFragment hfrag;
212 };
213 
214 /*
215  * The ErtsMessage struct is only one special type
216  * of signal. All signal structs have a common
217  * begining and can be differentiated by looking
218  * at the ErtsSignal 'common.tag' field.
219  *
220  * - An ordinary message will have a value
221  * - A distribution message that has not been
222  *   decoded yet will have the non-value.
223  * - Other signals will have an external pid
224  *   header tag. In order to differentiate
225  *   between those signals one needs to look
226  *   at the arity part of the header (see
227  *   erts_proc_sig_queue.h).
228  */
229 
230 #define ERTS_SIG_IS_NON_MSG_TAG(Tag) \
231     (is_external_pid_header((Tag)))
232 
233 #define ERTS_SIG_IS_NON_MSG(Sig) \
234     ERTS_SIG_IS_NON_MSG_TAG(((ErtsSignal *) (Sig))->common.tag)
235 
236 #define ERTS_SIG_IS_INTERNAL_MSG_TAG(Tag) \
237     (!is_header((Tag)))
238 #define ERTS_SIG_IS_INTERNAL_MSG(Sig) \
239     ERTS_SIG_IS_INTERNAL_MSG_TAG(((ErtsSignal *) (Sig))->common.tag)
240 
241 #define ERTS_SIG_IS_EXTERNAL_MSG_TAG(Tag) \
242     ((Tag) == THE_NON_VALUE)
243 #define ERTS_SIG_IS_EXTERNAL_MSG(Sig) \
244     ERTS_SIG_IS_EXTERNAL_MSG_TAG(((ErtsSignal *) (Sig))->common.tag)
245 
246 #define ERTS_SIG_IS_MSG_TAG(Tag) \
247     (!ERTS_SIG_IS_NON_MSG_TAG(Tag))
248 #define ERTS_SIG_IS_MSG(Sig) \
249     ERTS_SIG_IS_MSG_TAG(((ErtsSignal *) (Sig))->common.tag)
250 
251 typedef union {
252     ErtsSignalCommon common;
253     ErtsMessageRef msg;
254 } ErtsSignal;
255 
256 typedef struct {
257     /* pointers to next pointers pointing to... */
258     ErtsMessage **next; /* ... next (non-message) signal */
259     ErtsMessage **last; /* ... last (non-message) signal */
260 } ErtsMsgQNMSigs;
261 
262 typedef struct {
263     ErtsSignal sig;
264     ErtsMessage **prev_next;
265     signed char pass;
266     signed char set_save;
267     signed char in_sigq;
268     signed char in_msgq;
269     signed char prev_ix;
270     signed char next_ix;
271 #ifdef DEBUG
272     signed char used;
273     Process *proc;
274 #endif
275 } ErtsRecvMarker;
276 
277 #define ERTS_RECV_MARKER_BLOCK_SIZE 8
278 
279 typedef struct {
280     Eterm ref[ERTS_RECV_MARKER_BLOCK_SIZE];
281     ErtsRecvMarker marker[ERTS_RECV_MARKER_BLOCK_SIZE];
282     signed char free_ix;
283     signed char used_ix;
284     signed char unused;
285     signed char pending_set_save_ix;
286 #ifdef ERTS_SUPPORT_OLD_RECV_MARK_INSTRS
287     signed char old_recv_marker_ix;
288 #endif
289 } ErtsRecvMarkerBlock;
290 
291 /* Size of default message buffer (erl_message.c) */
292 #define ERL_MESSAGE_BUF_SZ 500
293 
294 typedef struct {
295     /*
296      * ** The signal queues private to a process. **
297      *
298      * These are:
299      * - an inner queue which only consists of
300      *   message signals
301      * - a middle queue which contains a mixture
302      *   of message and non-message signals
303      *
304      * When the process isn't processing signals in
305      * erts_proc_sig_handle_incoming():
306      * - the message queue corresponds to the inner
307      *   queue. Messages in the middle queue (and
308      *   in the outer queue) are in transit and
309      *   have NOT been received yet!
310      *
311      * When the process is processing signals in
312      * erts_proc_sig_handle_incoming():
313      * - the message queue corresponds to the inner
314      *   queue plus the head of the middle queue up
315      *   to the signal currently being processed.
316      *   Any messages further back in the middle queue
317      *   (and in the outer queue) are still in transit
318      *   and have NOT been received yet!
319      *
320      * In the general case the 'len' field of this
321      * structure does NOT correspond to the message
322      * queue length. When the process is inspected
323      * via process info it does however correspond
324      * to the message queue length, but this is a
325      * special case!
326      *
327      * When no process-info request is in transit to
328      * the process the 'len' field corresponds to
329      * the total amount of messages in inner and
330      * middle queues (which does NOT correspond to
331      * the message queue length). When process-info
332      * requests are in transit to the process, the
333      * usage of the 'len' field changes and is used
334      * as an offset which even might be negative.
335      */
336 
337     /* inner queue */
338     ErtsMessage *first;
339     ErtsMessage **last;  /* point to the last next pointer */
340     ErtsMessage **save;
341 
342     /* middle queue */
343     ErtsMessage *cont;
344     ErtsMessage **cont_last;
345     ErtsMsgQNMSigs nmsigs;
346 
347     /* Common for inner and middle queue */
348     ErtsRecvMarkerBlock *recv_mrk_blk;
349     Sint len; /* NOT message queue length (see above) */
350     Uint32 flags;
351 } ErtsSignalPrivQueues;
352 
353 typedef struct {
354     ErtsMessage* first;
355     ErtsMessage** last;  /* point to the last next pointer */
356     Sint len;            /* number of messages in queue */
357     ErtsMsgQNMSigs nmsigs;
358 #ifdef ERTS_PROC_SIG_HARD_DEBUG
359     int may_contain_heap_terms;
360 #endif
361 } ErtsSignalInQueue;
362 
363 typedef struct erl_trace_message_queue__ {
364     struct erl_trace_message_queue__ *next; /* point to the next receiver */
365     Eterm receiver;
366     ErtsMessage* first;
367     ErtsMessage** last;  /* point to the last next pointer */
368     Sint len;            /* queue length */
369 } ErlTraceMessageQueue;
370 
371 /* Get "current" message */
372 
373 #ifdef USE_VM_PROBES
374 #define LINK_MESSAGE_DTAG(mp, dt) ERL_MESSAGE_DT_UTAG(mp) = dt
375 #else
376 #define LINK_MESSAGE_DTAG(mp, dt)
377 #endif
378 
379 #ifdef USE_VM_PROBES
380 #  define ERTS_MSG_RECV_TRACED(P)                                       \
381     ((ERTS_TRACE_FLAGS((P)) & F_TRACE_RECEIVE)                          \
382      || DTRACE_ENABLED(message_queued))
383 #else
384 #  define ERTS_MSG_RECV_TRACED(P)                                       \
385     (ERTS_TRACE_FLAGS((P)) & F_TRACE_RECEIVE)
386 
387 #endif
388 
389 /* Add one message last in message queue */
390 #define LINK_MESSAGE(p, msg) \
391     do {                                                                \
392         ASSERT(ERTS_SIG_IS_MSG(msg));                                   \
393         ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE__((p), "before");               \
394         *(p)->sig_inq.last = (msg);                                     \
395         (p)->sig_inq.last = &(msg)->next;                               \
396         (p)->sig_inq.len++;                                             \
397         ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE__((p), "after");                \
398     } while(0)
399 
400 #define ERTS_HEAP_FRAG_SIZE(DATA_WORDS) \
401    (sizeof(ErlHeapFragment) - sizeof(Eterm) + (DATA_WORDS)*sizeof(Eterm))
402 
403 #define ERTS_INIT_HEAP_FRAG(HEAP_FRAG_P, USED_WORDS, DATA_WORDS)	\
404     do {								\
405 	(HEAP_FRAG_P)->next = NULL;					\
406 	(HEAP_FRAG_P)->alloc_size = (DATA_WORDS);			\
407 	(HEAP_FRAG_P)->used_size = (USED_WORDS);			\
408 	(HEAP_FRAG_P)->off_heap.first = NULL;				\
409 	(HEAP_FRAG_P)->off_heap.overhead = 0;				\
410     } while (0)
411 
412 #ifdef USE_VM_PROBES
413 #define ERL_MESSAGE_DT_UTAG_INIT(MP) ERL_MESSAGE_DT_UTAG(MP) = NIL
414 #else
415 #define ERL_MESSAGE_DT_UTAG_INIT(MP) do{ } while (0)
416 #endif
417 
418 #define ERTS_INIT_MESSAGE(MP)                           \
419     do {                                                \
420         (MP)->next = NULL;                              \
421         ERL_MESSAGE_TERM(MP) = THE_NON_VALUE;           \
422         ERL_MESSAGE_TOKEN(MP) = THE_NON_VALUE;          \
423         ERL_MESSAGE_FROM(MP) = NIL;                     \
424         ERL_MESSAGE_DT_UTAG_INIT(MP);                   \
425         MP->data.attached = NULL;                       \
426     } while (0)
427 
428 void init_message(void);
429 ErlHeapFragment* new_message_buffer(Uint);
430 ErlHeapFragment* erts_resize_message_buffer(ErlHeapFragment *, Uint,
431 					    Eterm *, Uint);
432 void free_message_buffer(ErlHeapFragment *);
433 void erts_queue_dist_message(Process*, ErtsProcLocks, ErtsDistExternal *,
434                              ErlHeapFragment *, Eterm, Eterm);
435 void erts_queue_message(Process*, ErtsProcLocks,ErtsMessage*, Eterm, Eterm);
436 void erts_queue_message_token(Process*, ErtsProcLocks,ErtsMessage*, Eterm, Eterm, Eterm);
437 void erts_queue_proc_message(Process* from,Process* to, ErtsProcLocks,ErtsMessage*, Eterm);
438 void erts_queue_proc_messages(Process* from, Process* to, ErtsProcLocks,
439                               ErtsMessage*, ErtsMessage**, Uint);
440 void erts_deliver_exit_message(Eterm, Process*, ErtsProcLocks *, Eterm, Eterm);
441 void erts_send_message(Process*, Process*, ErtsProcLocks*, Eterm);
442 void erts_link_mbuf_to_proc(Process *proc, ErlHeapFragment *bp);
443 
444 Uint erts_msg_attached_data_size_aux(ErtsMessage *msg);
445 
446 void erts_cleanup_offheap(ErlOffHeap *offheap);
447 void erts_save_message_in_proc(Process *p, ErtsMessage *msg);
448 Sint erts_move_messages_off_heap(Process *c_p);
449 Sint erts_complete_off_heap_message_queue_change(Process *c_p);
450 Eterm erts_change_message_queue_management(Process *c_p, Eterm new_state);
451 
452 void erts_cleanup_messages(ErtsMessage *mp);
453 
454 void *erts_alloc_message_ref(void);
455 void erts_free_message_ref(void *);
456 
457 #define ERTS_SMALL_FIX_MSG_SZ 10
458 #define ERTS_MEDIUM_FIX_MSG_SZ 20
459 #define ERTS_LARGE_FIX_MSG_SZ 30
460 
461 void *erts_alloc_small_message(void);
462 void erts_free_small_message(void *mp);
463 
464 typedef struct {
465     ErtsMessage m;
466     Eterm data[ERTS_SMALL_FIX_MSG_SZ-1];
467 } ErtsSmallFixSzMessage;
468 
469 typedef struct {
470     ErtsMessage m;
471     Eterm data[ERTS_MEDIUM_FIX_MSG_SZ-1];
472 } ErtsMediumFixSzMessage;
473 
474 typedef struct {
475     ErtsMessage m;
476     Eterm data[ERTS_LARGE_FIX_MSG_SZ-1];
477 } ErtsLargeFixSzMessage;
478 
479 ErtsMessage *erts_try_alloc_message_on_heap(Process *pp,
480 					    erts_aint32_t *psp,
481 					    ErtsProcLocks *plp,
482 					    Uint sz,
483 					    Eterm **hpp,
484 					    ErlOffHeap **ohpp,
485 					    int *on_heap_p);
486 ErtsMessage *erts_realloc_shrink_message(ErtsMessage *mp, Uint sz,
487 					 Eterm *brefs, Uint brefs_size);
488 
489 ERTS_GLB_FORCE_INLINE ErtsMessage *erts_alloc_message(Uint sz, Eterm **hpp);
490 ERTS_GLB_FORCE_INLINE ErtsMessage *erts_shrink_message(ErtsMessage *mp, Uint sz,
491 						       Eterm *brefs, Uint brefs_size);
492 ERTS_GLB_FORCE_INLINE void erts_free_message(ErtsMessage *mp);
493 ERTS_GLB_INLINE Uint erts_used_frag_sz(const ErlHeapFragment*);
494 ERTS_GLB_INLINE Uint erts_msg_attached_data_size(ErtsMessage *msg);
495 
496 #define ERTS_MSG_COMBINED_HFRAG ((void *) 0x1)
497 
498 #define erts_message_to_heap_frag(MP)                   \
499     (((MP)->data.attached == ERTS_MSG_COMBINED_HFRAG) ? \
500         &(MP)->hfrag : (MP)->data.heap_frag)
501 
502 #if ERTS_GLB_INLINE_INCL_FUNC_DEF
503 
erts_alloc_message(Uint sz,Eterm ** hpp)504 ERTS_GLB_FORCE_INLINE ErtsMessage *erts_alloc_message(Uint sz, Eterm **hpp)
505 {
506     ErtsMessage *mp;
507 
508     if (sz == 0) {
509 	mp = (ErtsMessage *)erts_alloc_message_ref();
510         ERTS_INIT_MESSAGE(mp);
511 	if (hpp)
512 	    *hpp = NULL;
513 	return mp;
514     }
515 
516     mp = (ErtsMessage *)erts_alloc(
517         ERTS_ALC_T_MSG, sizeof(ErtsMessage) + (sz - 1)*sizeof(Eterm));
518 
519     ERTS_INIT_MESSAGE(mp);
520     mp->data.attached = ERTS_MSG_COMBINED_HFRAG;
521     ERTS_INIT_HEAP_FRAG(&mp->hfrag, sz, sz);
522 
523     if (hpp)
524 	*hpp = &mp->hfrag.mem[0];
525 
526     return mp;
527 }
528 
529 ERTS_GLB_FORCE_INLINE ErtsMessage *
erts_shrink_message(ErtsMessage * mp,Uint sz,Eterm * brefs,Uint brefs_size)530 erts_shrink_message(ErtsMessage *mp, Uint sz, Eterm *brefs, Uint brefs_size)
531 {
532     if (sz == 0) {
533 	ErtsMessage *nmp;
534 	if (!mp->data.attached)
535 	    return mp;
536 	ASSERT(mp->data.attached == ERTS_MSG_COMBINED_HFRAG);
537 	nmp = (ErtsMessage *)erts_alloc_message_ref();
538 #ifdef DEBUG
539 	if (brefs && brefs_size) {
540 	    int i;
541 	    for (i = 0; i < brefs_size; i++)
542 		ASSERT(is_non_value(brefs[i]) || is_immed(brefs[i]));
543 	}
544 #endif
545 	erts_free(ERTS_ALC_T_MSG, mp);
546 	return nmp;
547     }
548 
549     ASSERT(mp->data.attached == ERTS_MSG_COMBINED_HFRAG);
550     ASSERT(mp->hfrag.used_size >= sz);
551 
552     if (sz >= (mp->hfrag.alloc_size - mp->hfrag.alloc_size / 16)) {
553 	mp->hfrag.used_size = sz;
554 	return mp;
555     }
556 
557     return erts_realloc_shrink_message(mp, sz, brefs, brefs_size);
558 }
559 
erts_free_message(ErtsMessage * mp)560 ERTS_GLB_FORCE_INLINE void erts_free_message(ErtsMessage *mp)
561 {
562     if (mp->data.attached != ERTS_MSG_COMBINED_HFRAG)
563 	erts_free_message_ref(mp);
564     else
565 	erts_free(ERTS_ALC_T_MSG, mp);
566 }
567 
erts_used_frag_sz(const ErlHeapFragment * bp)568 ERTS_GLB_INLINE Uint erts_used_frag_sz(const ErlHeapFragment* bp)
569 {
570     Uint sz = 0;
571     for ( ; bp!=NULL; bp=bp->next) {
572 	sz += bp->used_size;
573     }
574     return sz;
575 }
576 
erts_msg_attached_data_size(ErtsMessage * msg)577 ERTS_GLB_INLINE Uint erts_msg_attached_data_size(ErtsMessage *msg)
578 {
579     ASSERT(msg->data.attached);
580 
581     if (ERTS_SIG_IS_INTERNAL_MSG(msg))
582 	return erts_used_frag_sz(erts_message_to_heap_frag(msg));
583 
584     return erts_msg_attached_data_size_aux(msg);
585 }
586 
587 #endif
588 
589 Uint erts_mbuf_size(Process *p);
590 #if defined(DEBUG) || 0
591 #  define ERTS_CHK_MBUF_SZ(P)				\
592     do {						\
593 	Uint actual_mbuf_sz__ = erts_mbuf_size((P));	\
594 	ERTS_ASSERT((P)->mbuf_sz >= actual_mbuf_sz__);	\
595     } while (0)
596 #else
597 #  define ERTS_CHK_MBUF_SZ(P) ((void) 1)
598 #endif
599 
600 #define ERTS_FOREACH_SIG_PRIVQS(PROC, MVAR, CODE)                       \
601     do {                                                                \
602         int i__;                                                        \
603         ErtsMessage *msgs__[2] = {(PROC)->sig_qs.first,                 \
604                                   (PROC)->sig_qs.cont};                 \
605         for (i__ = 0; i__ < sizeof(msgs__)/sizeof(msgs__[0]); i__++) {  \
606             ErtsMessage *MVAR;                                          \
607             for (MVAR = msgs__[i__]; MVAR; MVAR = MVAR->next) {         \
608                 CODE;                                                   \
609             }                                                           \
610         }                                                               \
611     } while (0)
612 
613 #endif
614