diff options
Diffstat (limited to 'erts/emulator/beam/erl_message.h')
-rw-r--r-- | erts/emulator/beam/erl_message.h | 251 |
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 |