static int try_seize_update_permission(Process* c_p) { int success; ASSERT(!erts_thr_progress_is_blocking()); /* to avoid deadlock */ ASSERT(c_p != NULL); erts_mtx_lock(&update_table_permission_mtx); ASSERT(updater_process != c_p); success = (updater_process == NULL); if (success) { updater_process = c_p; } else { struct update_queue_item* qitem; qitem = erts_alloc(ERTS_ALC_T_PERSISTENT_LOCK_Q, sizeof(*qitem)); qitem->p = c_p; erts_proc_inc_refc(c_p); qitem->next = update_queue; update_queue = qitem; erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL); } erts_mtx_unlock(&update_table_permission_mtx); return success; }
static void * signal_dispatcher_thread_func(void *unused) { #ifdef ERTS_ENABLE_LOCK_CHECK erts_lc_set_thread_name("signal_dispatcher"); #endif while (1) { union {int signum; char buf[4];} sb; Eterm signal; int res, i = 0; /* Block on read() waiting for a signal notification to arrive... */ do { res = read(sig_notify_fds[0], (void *) &sb.buf[i], sizeof(int) - i); i += res > 0 ? res : 0; } while ((i < sizeof(int) && res >= 0) || (res < 0 && errno == EINTR)); if (res < 0) { erts_exit(ERTS_ABORT_EXIT, "signal-dispatcher thread got unexpected error: %s (%d)\n", erl_errno_id(errno), errno); } /* * NOTE 1: The signal dispatcher thread should not do work * that takes a substantial amount of time (except * perhaps in test and debug builds). It needs to * be responsive, i.e, it should only dispatch work * to other threads. * * NOTE 2: The signal dispatcher thread is not a blockable * thread (i.e., not a thread managed by the * erl_thr_progress module). This is intentional. * We want to be able to interrupt writing of a crash * dump by hitting C-c twice. Since it isn't a * blockable thread it is important that it doesn't * change the state of any data that a blocking thread * expects to have exclusive access to (unless the * signal dispatcher itself explicitly is blocking all * blockable threads). */ switch (sb.signum) { case 0: continue; case SIGINT: break_requested(); break; default: if ((signal = signum_to_signalterm(sb.signum)) == am_error) { erts_exit(ERTS_ABORT_EXIT, "signal-dispatcher thread received unknown " "signal notification: '%d'\n", sb.signum); } signal_notify_requested(signal); } ERTS_SMP_LC_ASSERT(!erts_thr_progress_is_blocking()); } return NULL; }
static void node_table_free(void *venp) { ErlNode *enp = (ErlNode *) venp; ERTS_SMP_LC_ASSERT(enp != erts_this_node || erts_thr_progress_is_blocking()); erts_deref_dist_entry(enp->dist_entry); #ifdef DEBUG sys_memset(venp, 0x55, sizeof(ErlNode)); #endif erts_free(ERTS_ALC_T_NODE_ENTRY, venp); ASSERT(node_entries > 0); node_entries--; }
void erts_set_this_node(Eterm sysname, Uint creation) { ERTS_SMP_LC_ASSERT(erts_thr_progress_is_blocking()); ASSERT(erts_refc_read(&erts_this_dist_entry->refc, 2)); if (erts_refc_dectest(&erts_this_node->refc, 0) == 0) try_delete_node(erts_this_node); if (erts_refc_dectest(&erts_this_dist_entry->refc, 0) == 0) try_delete_dist_entry(erts_this_dist_entry); erts_this_node = NULL; /* to make sure refc is bumped for this node */ erts_this_node = erts_find_or_insert_node(sysname, creation); erts_this_dist_entry = erts_this_node->dist_entry; erts_refc_inc(&erts_this_dist_entry->refc, 2); erts_this_node_sysname = erts_this_node_sysname_BUFFER; erts_snprintf(erts_this_node_sysname, sizeof(erts_this_node_sysname_BUFFER), "%T", sysname); }
/* * Called from schedule() when it runs out of runnable processes, * or when Erlang code has performed INPUT_REDUCTIONS reduction * steps. runnable == 0 iff there are no runnable Erlang processes. */ void erl_sys_schedule(int runnable) { ERTS_CHK_IO(!runnable); ERTS_SMP_LC_ASSERT(!erts_thr_progress_is_blocking()); }