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