aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_message.h
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/erl_message.h')
-rw-r--r--erts/emulator/beam/erl_message.h251
1 files changed, 251 insertions, 0 deletions
diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h
new file mode 100644
index 0000000000..f14f14a586
--- /dev/null
+++ b/erts/emulator/beam/erl_message.h
@@ -0,0 +1,251 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1997-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef __ERL_MESSAGE_H__
+#define __ERL_MESSAGE_H__
+
+struct proc_bin;
+struct external_thing_;
+
+/*
+ * This struct represents data that must be updated by structure copy,
+ * but is stored outside of any heap.
+ */
+
+typedef struct erl_off_heap {
+ struct proc_bin* mso; /* List of associated binaries. */
+#ifndef HYBRID /* FIND ME! */
+ struct erl_fun_thing* funs; /* List of funs. */
+#endif
+ struct external_thing_* externals; /* List of external things. */
+ int overhead; /* Administrative overhead (used to force GC). */
+} ErlOffHeap;
+
+#include "external.h"
+#include "erl_process.h"
+
+/*
+ * This struct represents a heap fragment, which is used when there
+ * isn't sufficient room in the process heap and we can't do a GC.
+ */
+
+typedef struct erl_heap_fragment ErlHeapFragment;
+struct erl_heap_fragment {
+ ErlHeapFragment* next; /* Next heap fragment */
+ ErlOffHeap off_heap; /* Offset heap data. */
+ unsigned size; /* Size in words of mem */
+ Eterm mem[1]; /* Data */
+};
+
+#define ERTS_SET_MBUF_HEAP_END(BP, HENDP) \
+do { \
+ unsigned real_size__ = (BP)->size; \
+ ASSERT((BP)->mem <= (HENDP) && (HENDP) <= (BP)->mem + real_size__); \
+ (BP)->size = (HENDP) - (BP)->mem; \
+ /* We do not reallocate since buffer *might* be moved. */ \
+ /* FIXME: Memory count is wrong, but at least it's almost */ \
+ /* right... */ \
+} while (0)
+
+typedef struct erl_mesg {
+ struct erl_mesg* next; /* Next message */
+ union {
+ ErtsDistExternal *dist_ext;
+ ErlHeapFragment *heap_frag;
+ void *attached;
+ } data;
+ Eterm m[2]; /* m[0] = message, m[1] = seq trace token */
+} ErlMessage;
+
+#define ERL_MESSAGE_TERM(mp) ((mp)->m[0])
+#define ERL_MESSAGE_TOKEN(mp) ((mp)->m[1])
+
+/* Size of default message buffer (erl_message.c) */
+#define ERL_MESSAGE_BUF_SZ 500
+
+typedef struct {
+ ErlMessage* first;
+ ErlMessage** last; /* point to the last next pointer */
+ ErlMessage** save;
+ int len; /* queue length */
+} ErlMessageQueue;
+
+#ifdef ERTS_SMP
+
+typedef struct {
+ ErlMessage* first;
+ ErlMessage** last; /* point to the last next pointer */
+ int len; /* queue length */
+} ErlMessageInQueue;
+
+#endif
+
+/* Get "current" message */
+#define PEEK_MESSAGE(p) (*(p)->msg.save)
+
+
+/* Add message last in private message queue */
+#define LINK_MESSAGE_PRIVQ(p, mp) do { \
+ *(p)->msg.last = (mp); \
+ (p)->msg.last = &(mp)->next; \
+ (p)->msg.len++; \
+} while(0)
+
+
+#ifdef ERTS_SMP
+
+/* Move in message queue to end of private message queue */
+#define ERTS_SMP_MSGQ_MV_INQ2PRIVQ(P) \
+do { \
+ if ((P)->msg_inq.first) { \
+ *(P)->msg.last = (P)->msg_inq.first; \
+ (P)->msg.last = (P)->msg_inq.last; \
+ (P)->msg.len += (P)->msg_inq.len; \
+ (P)->msg_inq.first = NULL; \
+ (P)->msg_inq.last = &(P)->msg_inq.first; \
+ (P)->msg_inq.len = 0; \
+ } \
+} while (0)
+
+/* Add message last in message queue */
+#define LINK_MESSAGE(p, mp) do { \
+ *(p)->msg_inq.last = (mp); \
+ (p)->msg_inq.last = &(mp)->next; \
+ (p)->msg_inq.len++; \
+} while(0)
+
+#else
+
+#define ERTS_SMP_MSGQ_MV_INQ2PRIVQ(P)
+
+/* Add message last in message queue */
+#define LINK_MESSAGE(p, mp) LINK_MESSAGE_PRIVQ((p), (mp))
+
+#endif
+
+/* Unlink current message */
+#define UNLINK_MESSAGE(p,msgp) do { \
+ ErlMessage* __mp = (msgp)->next; \
+ *(p)->msg.save = __mp; \
+ (p)->msg.len--; \
+ if (__mp == NULL) \
+ (p)->msg.last = (p)->msg.save; \
+} while(0)
+
+/* Reset message save point (after receive match) */
+#define JOIN_MESSAGE(p) \
+ (p)->msg.save = &(p)->msg.first
+
+/* Save current message */
+#define SAVE_MESSAGE(p) \
+ (p)->msg.save = &(*(p)->msg.save)->next
+
+/*
+ * ErtsMoveMsgAttachmentIntoProc() moves data attached to a message
+ * onto the heap of a process. The attached data is the content of
+ * the the message either on the internal format or on the external
+ * format, and also possibly a seq trace token on the internal format.
+ * If the message content is on the external format, the decode might
+ * fail. If the decoding fails, ERL_MESSAGE_TERM(M) will contain
+ * THE_NON_VALUE. That is, ERL_MESSAGE_TERM(M) *has* to be checked
+ * afterwards and taken care of appropriately.
+ *
+ * ErtsMoveMsgAttachmentIntoProc() will shallow copy to heap if
+ * possible; otherwise, move to heap via garbage collection.
+ *
+ * ErtsMoveMsgAttachmentIntoProc() is used when receiveing messages
+ * in process_main() and in hipe_check_get_msg().
+ */
+
+#define ErtsMoveMsgAttachmentIntoProc(M, P, ST, HT, FC, SWPO, SWPI) \
+do { \
+ if ((M)->data.attached) { \
+ Uint need__ = erts_msg_attached_data_size((M)); \
+ if ((ST) - (HT) >= need__) { \
+ Uint *htop__ = (HT); \
+ erts_move_msg_attached_data_to_heap(&htop__, &MSO((P)), (M));\
+ ASSERT(htop__ - (HT) <= need__); \
+ (HT) = htop__; \
+ } \
+ else { \
+ { SWPO ; } \
+ (FC) -= erts_garbage_collect((P), 0, NULL, 0); \
+ { SWPI ; } \
+ } \
+ ASSERT(!(M)->data.attached); \
+ } \
+} while (0)
+
+#define ERTS_SND_FLG_NO_SEQ_TRACE (((unsigned) 1) << 0)
+
+#define ERTS_HEAP_FRAG_SIZE(DATA_WORDS) \
+ (sizeof(ErlHeapFragment) - sizeof(Eterm) + (DATA_WORDS)*sizeof(Eterm))
+#define ERTS_INIT_HEAP_FRAG(HEAP_FRAG_P, DATA_WORDS) \
+do { \
+ (HEAP_FRAG_P)->next = NULL; \
+ (HEAP_FRAG_P)->size = (DATA_WORDS); \
+ (HEAP_FRAG_P)->off_heap.mso = NULL; \
+ (HEAP_FRAG_P)->off_heap.funs = NULL; \
+ (HEAP_FRAG_P)->off_heap.externals = NULL; \
+ (HEAP_FRAG_P)->off_heap.overhead = 0; \
+} while (0)
+
+void init_message(void);
+void free_message(ErlMessage *);
+ErlHeapFragment* new_message_buffer(Uint);
+ErlHeapFragment* erts_resize_message_buffer(ErlHeapFragment *, Uint,
+ Eterm *, Uint);
+void free_message_buffer(ErlHeapFragment *);
+void erts_queue_dist_message(Process*, ErtsProcLocks*, ErtsDistExternal *, Eterm);
+void erts_queue_message(Process*, ErtsProcLocks*, ErlHeapFragment*, Eterm, Eterm);
+void erts_deliver_exit_message(Eterm, Process*, ErtsProcLocks *, Eterm, Eterm);
+void erts_send_message(Process*, Process*, ErtsProcLocks*, Eterm, unsigned);
+void erts_link_mbuf_to_proc(Process *proc, ErlHeapFragment *bp);
+
+void erts_move_msg_mbuf_to_heap(Eterm**, ErlOffHeap*, ErlMessage *);
+
+Uint erts_msg_attached_data_size_aux(ErlMessage *msg);
+void erts_move_msg_attached_data_to_heap(Eterm **, ErlOffHeap *, ErlMessage *);
+
+Eterm erts_msg_distext2heap(Process *, ErtsProcLocks *, ErlHeapFragment **,
+ Eterm *, ErtsDistExternal *);
+
+ERTS_GLB_INLINE Uint erts_msg_attached_data_size(ErlMessage *msg);
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE Uint erts_msg_attached_data_size(ErlMessage *msg)
+{
+ ASSERT(msg->data.attached);
+ if (is_value(ERL_MESSAGE_TERM(msg)))
+ return msg->data.heap_frag->size;
+ else if (msg->data.dist_ext->heap_size < 0)
+ return erts_msg_attached_data_size_aux(msg);
+ else {
+ Uint sz = msg->data.dist_ext->heap_size;
+ if (is_not_nil(ERL_MESSAGE_TOKEN(msg))) {
+ ErlHeapFragment *heap_frag;
+ heap_frag = erts_dist_ext_trailer(msg->data.dist_ext);
+ sz += heap_frag->size;
+ }
+ return sz;
+ }
+}
+#endif
+
+#endif