/* --------------------------------------------------------------------------*/ int player_send_message(int pid, player_cmd_t *cmd) { player_cmd_t *mycmd; int r = -1; play_para_t *player_para; char buf[512]; player_para = player_open_pid_data(pid); if (player_para == NULL) { return PLAYER_NOT_VALID_PID; } if (player_get_state(pid) == PLAYER_EXIT) { player_close_pid_data(pid); return PLAYER_SUCCESS; } mycmd = message_alloc(); if (mycmd) { memcpy(mycmd, cmd, sizeof(*cmd)); r = send_message_by_pid(pid, mycmd); if (cmd2str(cmd, buf) != -1) { log_print("[%s]cmd = %s\n", __FUNCTION__, buf); } } else { r = PLAYER_NOMEM; } player_close_pid_data(pid); return r; }
/* --------------------------------------------------------------------------*/ int player_stop_async(int pid) { player_cmd_t *cmd; int r = PLAYER_SUCCESS; play_para_t *player_para; player_status sta; player_para = player_open_pid_data(pid); if (player_para == NULL) { return PLAYER_NOT_VALID_PID; } sta = get_player_state(player_para); log_print("[player_stop]player_status=%x\n", sta); if (PLAYER_THREAD_IS_STOPPED(sta)) { player_close_pid_data(pid); log_print("[player_stop]pid=%d thread is already stopped\n", pid); return PLAYER_SUCCESS; } cmd = message_alloc(); if (cmd) { cmd->ctrl_cmd = CMD_STOP; ffmpeg_interrupt(player_para->thread_mgt.pthread_id); r = send_message(player_para, cmd); } else { r = PLAYER_NOMEM; } player_close_pid_data(pid); return r; }
po_message_t po_message_create (void) { lex_pos_ty pos = { NULL, 0 }; return (po_message_t) message_alloc (NULL, NULL, NULL, NULL, 0, &pos); }
/* --------------------------------------------------------------------------*/ int player_start_play(int pid) { player_cmd_t *cmd; int r = PLAYER_SUCCESS; play_para_t *player_para; log_print("[player_start_play:enter]pid=%d\n", pid); player_para = player_open_pid_data(pid); if (player_para == NULL) { return PLAYER_NOT_VALID_PID; } cmd = message_alloc(); if (cmd) { cmd->ctrl_cmd = CMD_START; r = send_message(player_para, cmd); } else { r = PLAYER_NOMEM; } player_close_pid_data(pid); log_print("[player_start_play:exit]pid = %d\n", pid); return r; }
struct cfw_message * cfw_clone_message(struct cfw_message * msg) { struct cfw_message * ret = (struct cfw_message *) message_alloc(CFW_MESSAGE_LEN(msg), NULL); if (ret == NULL) { pr_error(LOG_MODULE_CFW, "%s: Error allocating message", __func__); } else { memcpy(ret, msg, CFW_MESSAGE_LEN(msg)); } return ret; }
static void circular_storage_shutdown(service_t *svc, struct cfw_message *msg) { struct cfw_message *sm = (struct cfw_message *)message_alloc( sizeof(*sm), NULL); /* In order to ensure that any pending requests are processed prior to the * service shutdown, send a message to self so it will be processed after * all other pending requests. */ CFW_MESSAGE_ID(sm) = MSG_ID_LL_CIRCULAR_STORAGE_SHUTDOWN_REQ; CFW_MESSAGE_DST(sm) = circular_storage_service.port_id; CFW_MESSAGE_SRC(sm) = circular_storage_service.port_id; CFW_MESSAGE_PRIV(sm) = msg; cfw_send_message(sm); }
/* --------------------------------------------------------------------------*/ int player_stop(int pid) { player_cmd_t *cmd; int r = PLAYER_SUCCESS; play_para_t *player_para; player_status sta; log_print("[player_stop:enter]pid=%d\n", pid); player_para = player_open_pid_data(pid); if (player_para == NULL) { return PLAYER_NOT_VALID_PID; } sta = get_player_state(player_para); log_print("[player_stop]player_status=%x\n", sta); if (PLAYER_THREAD_IS_STOPPED(sta)) { player_close_pid_data(pid); log_print("[player_stop]pid=%d thread is already stopped\n", pid); return PLAYER_SUCCESS; } /*if (player_para->pFormatCtx) { av_ioctrl(player_para->pFormatCtx, AVIOCTL_STOP, 0, 0); }*/ cmd = message_alloc(); if (cmd) { cmd->ctrl_cmd = CMD_STOP; ffmpeg_interrupt(player_para->thread_mgt.pthread_id); r = send_message(player_para, cmd); r = player_thread_wait_exit(player_para); log_print("[player_stop:%d]wait player_theadpid[%d] r = %d\n", __LINE__, player_para->player_id, r); clear_all_message(player_para); ffmpeg_uninterrupt(player_para->thread_mgt.pthread_id); } else { r = PLAYER_NOMEM; } player_close_pid_data(pid); log_print("[player_stop:exit]pid=%d\n", pid); return r; }
message_ty * message_copy (message_ty *mp) { message_ty *result; size_t j, i; result = message_alloc (mp->msgctxt != NULL ? xstrdup (mp->msgctxt) : NULL, xstrdup (mp->msgid), mp->msgid_plural, mp->msgstr, mp->msgstr_len, &mp->pos); if (mp->comment) { for (j = 0; j < mp->comment->nitems; ++j) message_comment_append (result, mp->comment->item[j]); } if (mp->comment_dot) { for (j = 0; j < mp->comment_dot->nitems; ++j) message_comment_dot_append (result, mp->comment_dot->item[j]); } result->is_fuzzy = mp->is_fuzzy; for (i = 0; i < NFORMATS; i++) result->is_format[i] = mp->is_format[i]; result->range = mp->range; result->do_wrap = mp->do_wrap; for (i = 0; i < NSYNTAXCHECKS; i++) result->do_syntax_check[i] = mp->do_syntax_check[i]; for (j = 0; j < mp->filepos_count; ++j) { lex_pos_ty *pp = &mp->filepos[j]; message_comment_filepos (result, pp->file_name, pp->line_number); } result->prev_msgctxt = (mp->prev_msgctxt != NULL ? xstrdup (mp->prev_msgctxt) : NULL); result->prev_msgid = (mp->prev_msgid != NULL ? xstrdup (mp->prev_msgid) : NULL); result->prev_msgid_plural = (mp->prev_msgid_plural != NULL ? xstrdup (mp->prev_msgid_plural) : NULL); return result; }
/* Delivers a notification which matches the receiver's subscription * expression */ static void notify_cb(elvin_handle_t handle, elvin_subscription_t subscription, elvin_notification_t notification, int is_secure, void *rock, elvin_error_t error) { usenet_sub_t self = (usenet_sub_t)rock; message_t message; elvin_basetypes_t type; elvin_value_t value; char *string; char *newsgroups; char *name; char *subject; char *mime_type; char *mime_args; char *attachment = NULL; size_t length; char *buffer = NULL; /* If we don't have a callback than bail out now */ if (self->callback == NULL) { return; } /* Get the newsgroups to which the message was posted */ if (elvin_notification_get(notification, NEWSGROUPS, &type, &value, error) && type == ELVIN_STRING) { string = value.s; } else { string = "news"; } /* Prepend `usenet:' to the beginning of the group field */ length = strlen(USENET_PREFIX) + strlen(string) - 1; newsgroups = malloc(length); if (newsgroups == NULL) { return; } snprintf(newsgroups, length, USENET_PREFIX, string); /* Get the name from the FROM_NAME field (if provided) */ if (elvin_notification_get(notification, FROM_NAME, &type, &value, error) && type == ELVIN_STRING) { name = value.s; } else { /* If no FROM_NAME field then try FROM_EMAIL */ if (elvin_notification_get(notification, FROM_EMAIL, &type, &value, error) && type == ELVIN_STRING) { name = value.s; } else { /* If no FROM_EMAIL then try FROM */ if (elvin_notification_get(notification, FROM, &type, &value, error) && type == ELVIN_STRING) { name = value.s; } else { name = "anonymous"; } } } /* Get the SUBJECT field (if provided) */ if (elvin_notification_get(notification, SUBJECT, &type, &value, error) && type == ELVIN_STRING) { subject = value.s; } else { subject = "[no subject]"; } /* Get the MIME_ARGS field (if provided) */ if (elvin_notification_get(notification, MIME_ARGS, &type, &value, error) && type == ELVIN_STRING) { mime_args = value.s; /* Get the MIME_TYPE field (if provided) */ if (elvin_notification_get(notification, MIME_TYPE, &type, &value, error) && type == ELVIN_STRING) { mime_type = value.s; } else { mime_type = URL_MIME_TYPE; } } else { /* No MIME_ARGS provided. Construct one using the Message-ID * field */ if (elvin_notification_get(notification, MESSAGE_ID, &type, &value, error) && type == ELVIN_STRING) { char *message_id = value.s; char *news_host; if (elvin_notification_get(notification, X_NNTP_HOST, &type, &value, error) && type == ELVIN_STRING) { news_host = value.s; } else { news_host = "news"; } length = strlen(NEWS_URL) + strlen(news_host) + strlen(message_id) - 3; buffer = malloc(length); if (buffer == NULL) { mime_type = NULL; mime_args = NULL; } else { snprintf(buffer, length, NEWS_URL, news_host, message_id); mime_args = buffer; mime_type = NEWS_MIME_TYPE; } } else { mime_type = NULL; mime_args = NULL; } } /* Convert the mime type and args into an attachment */ if (mime_type == NULL || mime_args == NULL) { attachment = NULL; length = 0; } else { length = strlen(ATTACHMENT_FMT) + strlen(mime_type) + strlen( mime_args) - 4; attachment = malloc(length + 1); if (attachment == NULL) { length = 0; } else { snprintf(attachment, length + 1, ATTACHMENT_FMT, mime_type, mime_args); } } /* Construct a message out of all of that */ message = message_alloc(NULL, newsgroups, name, subject, 300, attachment, length - 1, NULL, NULL, NULL, NULL); if (message != NULL) { /* Deliver the message */ self->callback(self->rock, message, False); } /* Clean up */ free(newsgroups); if (buffer != NULL) { free(buffer); } if (attachment != NULL) { free(attachment); } }
/* Reads an existing .mo file and adds the messages to mlp. */ void read_mo_file (message_list_ty *mlp, const char *filename) { FILE *fp; struct binary_mo_file bf; struct mo_file_header header; unsigned int i; static lex_pos_ty pos = { __FILE__, __LINE__ }; if (strcmp (filename, "-") == 0 || strcmp (filename, "/dev/stdin") == 0) { fp = stdin; SET_BINARY (fileno (fp)); } else { fp = fopen (filename, "rb"); if (fp == NULL) error (EXIT_FAILURE, errno, _("error while opening \"%s\" for reading"), filename); } /* Read the file contents into memory. */ read_binary_mo_file (&bf, fp, filename); /* Get a 32-bit number from the file header. */ # define GET_HEADER_FIELD(field) \ get_uint32 (&bf, offsetof (struct mo_file_header, field)) /* We must grope the file to determine which endian it is. Perversity of the universe tends towards maximum, so it will probably not match the currently executing architecture. */ bf.endian = MO_BIG_ENDIAN; header.magic = GET_HEADER_FIELD (magic); if (header.magic != _MAGIC) { bf.endian = MO_LITTLE_ENDIAN; header.magic = GET_HEADER_FIELD (magic); if (header.magic != _MAGIC) { unrecognised: error (EXIT_FAILURE, 0, _("file \"%s\" is not in GNU .mo format"), filename); } } header.revision = GET_HEADER_FIELD (revision); /* We support only the major revisions 0 and 1. */ switch (header.revision >> 16) { case 0: case 1: /* Fill the header parts that apply to major revisions 0 and 1. */ header.nstrings = GET_HEADER_FIELD (nstrings); header.orig_tab_offset = GET_HEADER_FIELD (orig_tab_offset); header.trans_tab_offset = GET_HEADER_FIELD (trans_tab_offset); header.hash_tab_size = GET_HEADER_FIELD (hash_tab_size); header.hash_tab_offset = GET_HEADER_FIELD (hash_tab_offset); for (i = 0; i < header.nstrings; i++) { message_ty *mp; char *msgid; size_t msgid_len; char *msgstr; size_t msgstr_len; /* Read the msgid. */ msgid = get_string (&bf, header.orig_tab_offset + i * 8, &msgid_len); /* Read the msgstr. */ msgstr = get_string (&bf, header.trans_tab_offset + i * 8, &msgstr_len); mp = message_alloc (msgid, (strlen (msgid) + 1 < msgid_len ? msgid + strlen (msgid) + 1 : NULL), msgstr, msgstr_len, &pos); message_list_append (mlp, mp); } switch (header.revision & 0xffff) { case 0: break; case 1: default: /* Fill the header parts that apply to minor revision >= 1. */ header.n_sysdep_segments = GET_HEADER_FIELD (n_sysdep_segments); header.sysdep_segments_offset = GET_HEADER_FIELD (sysdep_segments_offset); header.n_sysdep_strings = GET_HEADER_FIELD (n_sysdep_strings); header.orig_sysdep_tab_offset = GET_HEADER_FIELD (orig_sysdep_tab_offset); header.trans_sysdep_tab_offset = GET_HEADER_FIELD (trans_sysdep_tab_offset); for (i = 0; i < header.n_sysdep_strings; i++) { message_ty *mp; char *msgid; size_t msgid_len; char *msgstr; size_t msgstr_len; nls_uint32 offset; /* Read the msgid. */ offset = get_uint32 (&bf, header.orig_sysdep_tab_offset + i * 4); msgid = get_sysdep_string (&bf, offset, &header, &msgid_len); /* Read the msgstr. */ offset = get_uint32 (&bf, header.trans_sysdep_tab_offset + i * 4); msgstr = get_sysdep_string (&bf, offset, &header, &msgstr_len); mp = message_alloc (msgid, (strlen (msgid) + 1 < msgid_len ? msgid + strlen (msgid) + 1 : NULL), msgstr, msgstr_len, &pos); message_list_append (mlp, mp); } break; } break; default: goto unrecognised; } if (fp != stdin) fclose (fp); }
/* Reads an existing .mo file and adds the messages to mlp. */ void read_mo_file (message_list_ty *mlp, const char *filename) { FILE *fp; struct binary_mo_file bf; struct mo_file_header header; unsigned int i; static lex_pos_ty pos = { __FILE__, __LINE__ }; if (strcmp (filename, "-") == 0 || strcmp (filename, "/dev/stdin") == 0) { fp = stdin; SET_BINARY (fileno (fp)); } else { fp = fopen (filename, "rb"); if (fp == NULL) error (EXIT_FAILURE, errno, _("error while opening \"%s\" for reading"), filename); } /* Read the file contents into memory. */ read_binary_mo_file (&bf, fp, filename); /* Get a 32-bit number from the file header. */ # define GET_HEADER_FIELD(field) \ get_uint32 (&bf, offsetof (struct mo_file_header, field)) /* We must grope the file to determine which endian it is. Perversity of the universe tends towards maximum, so it will probably not match the currently executing architecture. */ bf.endian = MO_BIG_ENDIAN; header.magic = GET_HEADER_FIELD (magic); if (header.magic != _MAGIC) { bf.endian = MO_LITTLE_ENDIAN; header.magic = GET_HEADER_FIELD (magic); if (header.magic != _MAGIC) { unrecognised: error (EXIT_FAILURE, 0, _("file \"%s\" is not in GNU .mo format"), filename); } } header.revision = GET_HEADER_FIELD (revision); /* We support only the major revisions 0 and 1. */ switch (header.revision >> 16) { case 0: case 1: /* Fill the header parts that apply to major revisions 0 and 1. */ header.nstrings = GET_HEADER_FIELD (nstrings); header.orig_tab_offset = GET_HEADER_FIELD (orig_tab_offset); header.trans_tab_offset = GET_HEADER_FIELD (trans_tab_offset); header.hash_tab_size = GET_HEADER_FIELD (hash_tab_size); header.hash_tab_offset = GET_HEADER_FIELD (hash_tab_offset); for (i = 0; i < header.nstrings; i++) { message_ty *mp; char *msgctxt; char *msgid; size_t msgid_len; char *separator; char *msgstr; size_t msgstr_len; /* Read the msgctxt and msgid. */ msgid = get_string (&bf, header.orig_tab_offset + i * 8, &msgid_len); /* Split into msgctxt and msgid. */ separator = strchr (msgid, MSGCTXT_SEPARATOR); if (separator != NULL) { /* The part before the MSGCTXT_SEPARATOR is the msgctxt. */ *separator = '\0'; msgctxt = msgid; msgid = separator + 1; msgid_len -= msgid - msgctxt; } else msgctxt = NULL; /* Read the msgstr. */ msgstr = get_string (&bf, header.trans_tab_offset + i * 8, &msgstr_len); mp = message_alloc (msgctxt, msgid, (strlen (msgid) + 1 < msgid_len ? msgid + strlen (msgid) + 1 : NULL), msgstr, msgstr_len, &pos); message_list_append (mlp, mp); } switch (header.revision & 0xffff) { case 0: break; case 1: default: /* Fill the header parts that apply to minor revision >= 1. */ header.n_sysdep_segments = GET_HEADER_FIELD (n_sysdep_segments); header.sysdep_segments_offset = GET_HEADER_FIELD (sysdep_segments_offset); header.n_sysdep_strings = GET_HEADER_FIELD (n_sysdep_strings); header.orig_sysdep_tab_offset = GET_HEADER_FIELD (orig_sysdep_tab_offset); header.trans_sysdep_tab_offset = GET_HEADER_FIELD (trans_sysdep_tab_offset); for (i = 0; i < header.n_sysdep_strings; i++) { message_ty *mp; char *msgctxt; char *msgid; size_t msgid_len; char *separator; char *msgstr; size_t msgstr_len; nls_uint32 offset; size_t f; /* Read the msgctxt and msgid. */ offset = get_uint32 (&bf, header.orig_sysdep_tab_offset + i * 4); msgid = get_sysdep_string (&bf, offset, &header, &msgid_len); /* Split into msgctxt and msgid. */ separator = strchr (msgid, MSGCTXT_SEPARATOR); if (separator != NULL) { /* The part before the MSGCTXT_SEPARATOR is the msgctxt. */ *separator = '\0'; msgctxt = msgid; msgid = separator + 1; msgid_len -= msgid - msgctxt; } else msgctxt = NULL; /* Read the msgstr. */ offset = get_uint32 (&bf, header.trans_sysdep_tab_offset + i * 4); msgstr = get_sysdep_string (&bf, offset, &header, &msgstr_len); mp = message_alloc (msgctxt, msgid, (strlen (msgid) + 1 < msgid_len ? msgid + strlen (msgid) + 1 : NULL), msgstr, msgstr_len, &pos); /* Only messages with c-format or objc-format annotation are recognized as having system-dependent strings by msgfmt. Which one of the two, we don't know. We have to guess, assuming that c-format is more probable than objc-format and that the .mo was likely produced by "msgfmt -c". */ for (f = format_c; ; f = format_objc) { bool valid = true; struct formatstring_parser *parser = formatstring_parsers[f]; const char *str_end; const char *str; str_end = msgid + msgid_len; for (str = msgid; str < str_end; str += strlen (str) + 1) { char *invalid_reason = NULL; void *descr = parser->parse (str, false, NULL, &invalid_reason); if (descr != NULL) parser->free (descr); else { free (invalid_reason); valid = false; break; } } if (valid) { str_end = msgstr + msgstr_len; for (str = msgstr; str < str_end; str += strlen (str) + 1) { char *invalid_reason = NULL; void *descr = parser->parse (str, true, NULL, &invalid_reason); if (descr != NULL) parser->free (descr); else { free (invalid_reason); valid = false; break; } } } if (valid) { /* Found the most likely among c-format, objc-format. */ mp->is_format[f] = yes; break; } /* Try next f. */ if (f == format_objc) break; } message_list_append (mlp, mp); } break; } break; default: goto unrecognised; } if (fp != stdin) fclose (fp); }
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); } }
/* 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 }
void erts_send_message(Process* sender, Process* receiver, ErtsProcLocks *receiver_locks, Eterm message, unsigned flags) { Uint msize; ErlHeapFragment* bp = NULL; Eterm token = NIL; BM_STOP_TIMER(system); BM_MESSAGE(message,sender,receiver); BM_START_TIMER(send); if (SEQ_TRACE_TOKEN(sender) != NIL && !(flags & ERTS_SND_FLG_NO_SEQ_TRACE)) { Eterm* hp; BM_SWAP_TIMER(send,size); msize = size_object(message); BM_SWAP_TIMER(size,send); seq_trace_update_send(sender); seq_trace_output(SEQ_TRACE_TOKEN(sender), message, SEQ_TRACE_SEND, receiver->id, sender); bp = new_message_buffer(msize + 6 /* TUPLE5 */); hp = bp->mem; BM_SWAP_TIMER(send,copy); token = copy_struct(SEQ_TRACE_TOKEN(sender), 6 /* TUPLE5 */, &hp, &bp->off_heap); message = copy_struct(message, msize, &hp, &bp->off_heap); BM_MESSAGE_COPIED(msize); BM_SWAP_TIMER(copy,send); erts_queue_message(receiver, receiver_locks, bp, message, token); BM_SWAP_TIMER(send,system); #ifdef HYBRID } else { ErlMessage* mp = message_alloc(); BM_SWAP_TIMER(send,copy); #ifdef INCREMENTAL /* TODO: During GC activate processes if the message relies in * the fromspace and the sender is active. During major * collections add the message to the gray stack if it relies * in the old generation and the sender is active and the * receiver is inactive. if (!IS_CONST(message) && (ma_gc_flags & GC_CYCLE) && (ptr_val(message) >= inc_fromspc && ptr_val(message) < inc_fromend) && INC_IS_ACTIVE(sender)) INC_ACTIVATE(receiver); else if (!IS_CONST(message) && (ma_gc_flags & GC_CYCLE) && (ptr_val(message) >= global_old_heap && ptr_val(message) < global_old_hend) && INC_IS_ACTIVE(sender) && !INC_IS_ACTIVE(receiver)) Mark message in blackmap and add it to the gray stack */ if (!IS_CONST(message)) INC_ACTIVATE(receiver); #endif LAZY_COPY(sender,message); BM_SWAP_TIMER(copy,send); ERL_MESSAGE_TERM(mp) = message; ERL_MESSAGE_TOKEN(mp) = NIL; mp->next = NULL; LINK_MESSAGE(receiver, mp); ACTIVATE(receiver); if (receiver->status == P_WAITING) { erts_add_to_runq(receiver); } else if (receiver->status == P_SUSPENDED) { receiver->rstatus = P_RUNABLE; } if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)) { trace_receive(receiver, message); } BM_SWAP_TIMER(send,system); return; #else } else if (sender == receiver) {
/* Delivers a notification which matches the receiver's subscription * expression */ static int notify_cb(elvin_handle_t handle, elvin_subscription_t subscription, elvin_notification_t notification, int is_secure, void *rock, elvin_error_t error) { usenet_sub_t self = (usenet_sub_t)rock; message_t message; char *string; char *newsgroups; char *name; char *subject; char *mime_type; char *mime_args; char *buffer = NULL; char *attachment = NULL; size_t length = 0; int found; /* If we don't have a callback than bail out now */ if (self->callback == NULL) { return 1; } /* Get the newsgroups to which the message was posted */ if (!elvin_notification_get_string(notification, NEWSGROUPS, &found, &string, error)) { eeprintf(error, "elvin_notification_get_string failed\n"); exit(1); } /* Use a reasonable default */ string = found ? string : "news"; /* Prepend `usenet:' to the beginning of the group field */ length = strlen(USENET_PREFIX) + strlen(string) - 1; newsgroups = malloc(length); if (newsgroups == NULL) { return 0; } snprintf(newsgroups, length, USENET_PREFIX, string); /* Get the name from the FROM_NAME field (if provided) */ if (!elvin_notification_get_string(notification, FROM_NAME, &found, &name, error)) { eeprintf(error, "elvin_notification_get_string failed\n"); exit(1); } if (!found) { /* No FROM_NAME field, so try FROM_EMAIL */ if (!elvin_notification_get_string(notification, FROM_EMAIL, &found, &name, error)) { eeprintf(error, "elvin_notification_get_string failed\n"); exit(1); } if (!found) { /* No FROM_EMAIL, so try FROM */ if (!elvin_notification_get_string(notification, FROM, &found, &name, error)) { eeprintf(error, "elvin_notification_get_string failed\n"); exit(1); } if (!found) { /* Give up */ name = "anonymous"; } } } /* Get the SUBJECT field (if provided) */ if (!elvin_notification_get_string(notification, SUBJECT, &found, &subject, error)) { eeprintf(error, "elvin_notification_get_string failed\n"); exit(1); } /* Use a default if none found */ subject = found ? subject : "[no subject]"; /* Get the MIME_ARGS field (if provided) */ if (!elvin_notification_get_string(notification, MIME_ARGS, &found, &mime_args, error)) { eeprintf(error, "elvin_notification_get_string failed\n"); exit(1); } /* Was the MIME_ARGS field provided? */ if (found) { /* Get the MIME_TYPE field (if provided) */ if (!elvin_notification_get_string(notification, MIME_TYPE, &found, &mime_type, error)) { eeprintf(error, "elvin_notification_get_string failed\n"); exit(1); } /* Use a default if none found */ mime_type = found ? mime_type : URL_MIME_TYPE; } else { char *message_id; /* No MIME_ARGS. Look for a message-id */ if (!elvin_notification_get_string(notification, MESSAGE_ID, &found, &message_id, error)) { eeprintf(error, "elvin_notification_get_string failed\n"); exit(1); } if (found) { char *news_host; /* Look up the news host field */ if (!elvin_notification_get_string( notification, X_NNTP_HOST, &found, &news_host, error)) { eeprintf(error, "elvin_notification_get_string failed\n"); exit(1); } news_host = found ? news_host : "news"; length = strlen(NEWS_URL) + strlen(news_host) + strlen(message_id) - 3; buffer = malloc(length); if (buffer == NULL) { mime_type = NULL; mime_args = NULL; } else { snprintf(buffer, length, NEWS_URL, news_host, message_id); mime_args = buffer; mime_type = NEWS_MIME_TYPE; } } else { mime_type = NULL; mime_args = NULL; } } /* Convert the mime type and args into an attachment */ if (mime_type == NULL || mime_args == NULL) { attachment = NULL; length = 0; } else { length = strlen(ATTACHMENT_FMT) - 4 + strlen(mime_type) + strlen( mime_args); attachment = malloc(length + 1); if (attachment == NULL) { length = 0; } else { snprintf(attachment, length + 1, ATTACHMENT_FMT, mime_type, mime_args); } } /* Construct a message out of all of that */ message = message_alloc(NULL, newsgroups, name, subject, 60, attachment, length, NULL, NULL, NULL, NULL); if (message != NULL) { /* Deliver the message */ self->callback(self->rock, message, False); } /* Clean up */ free(newsgroups); if (buffer != NULL) { free(buffer); } return 1; }
Sint erts_send_message(Process* sender, Process* receiver, ErtsProcLocks *receiver_locks, Eterm message, unsigned flags) { Uint msize; ErlHeapFragment* bp = NULL; Eterm token = NIL; Sint res = 0; #ifdef USE_VM_PROBES DTRACE_CHARBUF(sender_name, 64); DTRACE_CHARBUF(receiver_name, 64); Sint tok_label = 0; Sint tok_lastcnt = 0; Sint tok_serial = 0; #endif BM_STOP_TIMER(system); BM_MESSAGE(message,sender,receiver); BM_START_TIMER(send); #ifdef USE_VM_PROBES *sender_name = *receiver_name = '\0'; if (DTRACE_ENABLED(message_send)) { erts_snprintf(sender_name, sizeof(DTRACE_CHARBUF_NAME(sender_name)), "%T", sender->common.id); erts_snprintf(receiver_name, sizeof(DTRACE_CHARBUF_NAME(receiver_name)), "%T", receiver->common.id); } #endif if (SEQ_TRACE_TOKEN(sender) != NIL && !(flags & ERTS_SND_FLG_NO_SEQ_TRACE)) { Eterm* hp; Eterm stoken = SEQ_TRACE_TOKEN(sender); Uint seq_trace_size = 0; #ifdef USE_VM_PROBES Uint dt_utag_size = 0; Eterm utag = NIL; #endif BM_SWAP_TIMER(send,size); msize = size_object(message); BM_SWAP_TIMER(size,send); #ifdef USE_VM_PROBES if (stoken != am_have_dt_utag) { #endif seq_trace_update_send(sender); seq_trace_output(stoken, message, SEQ_TRACE_SEND, receiver->common.id, sender); seq_trace_size = 6; /* TUPLE5 */ #ifdef USE_VM_PROBES } if (DT_UTAG_FLAGS(sender) & DT_UTAG_SPREADING) { dt_utag_size = size_object(DT_UTAG(sender)); } else if (stoken == am_have_dt_utag ) { stoken = NIL; } #endif bp = new_message_buffer(msize + seq_trace_size #ifdef USE_VM_PROBES + dt_utag_size #endif ); hp = bp->mem; BM_SWAP_TIMER(send,copy); token = copy_struct(stoken, seq_trace_size, &hp, &bp->off_heap); message = copy_struct(message, msize, &hp, &bp->off_heap); #ifdef USE_VM_PROBES if (DT_UTAG_FLAGS(sender) & DT_UTAG_SPREADING) { utag = copy_struct(DT_UTAG(sender), dt_utag_size, &hp, &bp->off_heap); #ifdef DTRACE_TAG_HARDDEBUG erts_fprintf(stderr, "Dtrace -> (%T) Spreading tag (%T) with " "message %T!\r\n",sender->common.id, utag, message); #endif } #endif BM_MESSAGE_COPIED(msize); BM_SWAP_TIMER(copy,send); #ifdef USE_VM_PROBES if (DTRACE_ENABLED(message_send)) { if (stoken != NIL && stoken != am_have_dt_utag) { tok_label = signed_val(SEQ_TRACE_T_LABEL(stoken)); tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(stoken)); tok_serial = signed_val(SEQ_TRACE_T_SERIAL(stoken)); } DTRACE6(message_send, sender_name, receiver_name, msize, tok_label, tok_lastcnt, tok_serial); } #endif res = queue_message(NULL, receiver, receiver_locks, NULL, bp, message, token #ifdef USE_VM_PROBES , utag #endif ); BM_SWAP_TIMER(send,system); } else if (sender == receiver) { /* Drop message if receiver has a pending exit ... */ #ifdef ERTS_SMP ErtsProcLocks 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 (!ERTS_PROC_PENDING_EXIT(receiver)) #endif { ErlMessage* mp = message_alloc(); DTRACE6(message_send, sender_name, receiver_name, size_object(message), tok_label, tok_lastcnt, tok_serial); mp->data.attached = NULL; ERL_MESSAGE_TERM(mp) = message; ERL_MESSAGE_TOKEN(mp) = NIL; #ifdef USE_VM_PROBES ERL_MESSAGE_DT_UTAG(mp) = NIL; #endif mp->next = NULL; /* * 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); res = receiver->msg.len; if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)) { trace_receive(receiver, message); } } BM_SWAP_TIMER(send,system); } else { ErlOffHeap *ohp; Eterm *hp; erts_aint32_t state; BM_SWAP_TIMER(send,size); msize = size_object(message); BM_SWAP_TIMER(size,send); hp = erts_alloc_message_heap_state(msize, &bp, &ohp, receiver, receiver_locks, &state); BM_SWAP_TIMER(send,copy); message = copy_struct(message, msize, &hp, ohp); BM_MESSAGE_COPIED(msz); BM_SWAP_TIMER(copy,send); DTRACE6(message_send, sender_name, receiver_name, msize, tok_label, tok_lastcnt, tok_serial); res = queue_message(sender, receiver, receiver_locks, &state, bp, message, token #ifdef USE_VM_PROBES , NIL #endif ); BM_SWAP_TIMER(send,system); } return res; }
/* Add a message last in message queue */ static Sint queue_message(Process *c_p, Process* receiver, ErtsProcLocks *receiver_locks, erts_aint32_t *receiver_state, ErlHeapFragment* bp, Eterm message, Eterm seq_trace_token #ifdef USE_VM_PROBES , Eterm dt_utag #endif ) { Sint res; ErlMessage* mp; int locked_msgq = 0; erts_aint_t state; #ifndef ERTS_SMP ASSERT(bp != NULL || receiver->mbuf == NULL); #endif ERTS_SMP_LC_ASSERT(*receiver_locks == erts_proc_lc_my_proc_locks(receiver)); mp = message_alloc(); if (receiver_state) state = *receiver_state; else state = erts_smp_atomic32_read_acqb(&receiver->state); #ifdef ERTS_SMP if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT)) goto exiting; if (!(*receiver_locks & ERTS_PROC_LOCK_MSGQ)) { if (erts_smp_proc_trylock(receiver, ERTS_PROC_LOCK_MSGQ) == EBUSY) { ErtsProcLocks need_locks = ERTS_PROC_LOCK_MSGQ; if (*receiver_locks & ERTS_PROC_LOCK_STATUS) { erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_STATUS); need_locks |= ERTS_PROC_LOCK_STATUS; } erts_smp_proc_lock(receiver, need_locks); } locked_msgq = 1; state = erts_smp_atomic32_read_nob(&receiver->state); if (receiver_state) *receiver_state = state; } #endif if (state & (ERTS_PSFLG_PENDING_EXIT|ERTS_PSFLG_EXITING)) { #ifdef ERTS_SMP exiting: #endif /* Drop message if receiver is exiting or has a pending exit... */ if (locked_msgq) erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ); if (bp) free_message_buffer(bp); message_free(mp); return 0; } 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; #ifndef ERTS_SMP res = receiver->msg.len; #else res = receiver->msg_inq.len; 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. */ res += receiver->msg.len; ERTS_SMP_MSGQ_MV_INQ2PRIVQ(receiver); LINK_MESSAGE_PRIVQ(receiver, mp); } else #endif { LINK_MESSAGE(receiver, mp); } #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 if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)) trace_receive(receiver, message); if (locked_msgq) erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ); erts_proc_notify_new_message(receiver, #ifdef ERTS_SMP *receiver_locks #else 0 #endif ); #ifndef ERTS_SMP ERTS_HOLE_CHECK(receiver); #endif return res; }
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 erts_aint_t state; #endif ERTS_SMP_LC_ASSERT(*rcvr_locks == erts_proc_lc_my_proc_locks(rcvr)); mp = message_alloc(); #ifdef ERTS_SMP if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ)) { if (erts_smp_proc_trylock(rcvr, ERTS_PROC_LOCK_MSGQ) == EBUSY) { ErtsProcLocks need_locks = ERTS_PROC_LOCK_MSGQ; if (*rcvr_locks & ERTS_PROC_LOCK_STATUS) { erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_STATUS); need_locks |= ERTS_PROC_LOCK_STATUS; } erts_smp_proc_lock(rcvr, need_locks); } } state = erts_smp_atomic32_read_acqb(&rcvr->state); if (state & (ERTS_PSFLG_PENDING_EXIT|ERTS_PSFLG_EXITING)) { if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ)) erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ); /* 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; if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ)) erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ); 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); } 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); if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ)) erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ); erts_proc_notify_new_message(rcvr, #ifdef ERTS_SMP *rcvr_locks #else 0 #endif ); } }
/* 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 }