Example #1
0
void
erts_thr_progress_fatal_error_wait(SWord timeout) {
    erts_aint32_t bc;
    SWord time_left = timeout;
    ErtsMonotonicTime timeout_time;
    ErtsSchedulerData *esdp = erts_get_scheduler_data();

    /*
     * Counting poll intervals may give us a too long timeout
     * if cpu is busy. We use timeout time to try to prevent
     * this. In case we havn't got time correction this may
     * however fail too...
     */
    timeout_time = erts_get_monotonic_time(esdp);
    timeout_time += ERTS_MSEC_TO_MONOTONIC((ErtsMonotonicTime) timeout);

    while (1) {
	if (erts_milli_sleep(ERTS_THR_PRGR_FTL_ERR_BLCK_POLL_INTERVAL) == 0)
	    time_left -= ERTS_THR_PRGR_FTL_ERR_BLCK_POLL_INTERVAL;
	bc = erts_atomic32_read_acqb(&intrnl->misc.data.block_count);
	if (bc == 0)
	    break; /* Succefully blocked all managed threads */
	if (time_left <= 0)
	    break; /* Timeout */
	if (timeout_time <= erts_get_monotonic_time(esdp))
	    break; /* Timeout */
    }
}
Example #2
0
void
erts_deep_process_dump(fmtfn_t to, void *to_arg)
{
    int i, max = erts_ptab_max(&erts_proc);

    all_binaries = NULL;
    init_literal_areas();
    erts_init_persistent_dumping();

    for (i = 0; i < max; i++) {
	Process *p = erts_pix2proc(i);
	if (p && p->i != ENULL) {
	    erts_aint32_t state = erts_atomic32_read_acqb(&p->state);
	    if (state & ERTS_PSFLG_EXITING)
                continue;
            if (state & ERTS_PSFLG_GC) {
                ErtsSchedulerData *sdp = erts_get_scheduler_data();
                if (!sdp || p != sdp->current_process)
                    continue;

                /* We want to dump the garbing process that caused the dump */
            }

            dump_process_info(to, to_arg, p);
       }
    }

    dump_persistent_terms(to, to_arg);
    dump_literals(to, to_arg);
    dump_binaries(to, to_arg, all_binaries);
}
Example #3
0
void erts_debug_unuse_tmp_heap(int size, Process *p)
{
    ErtsSchedulerData *sd = ((p == NULL) ? erts_get_scheduler_data() : ERTS_PROC_GET_SCHDATA(p));

    sd->num_tmp_heap_used -= size;
    ASSERT(sd->num_tmp_heap_used >= 0);
}
Example #4
0
Eterm *erts_debug_allocate_tmp_heap(int size, Process *p)
{
    ErtsSchedulerData *sd = ((p == NULL) ? erts_get_scheduler_data() : ERTS_PROC_GET_SCHDATA(p));
    int offset = sd->num_tmp_heap_used;

    ASSERT(offset+size <= TMP_HEAP_SIZE);
    return (sd->tmp_heap)+offset;
}
Example #5
0
static ERTS_INLINE void
make_ref_in_array(Uint32 ref[ERTS_MAX_REF_NUMBERS])
{
    ErtsSchedulerData *esdp = erts_get_scheduler_data();
    if (esdp)
	erts_sched_make_ref_in_array(esdp, ref);
    else
	global_make_ref_in_array(0, ref);
}
Example #6
0
void
erts_raw_get_unique_integer(Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES])
{
    ErtsSchedulerData *esdp = erts_get_scheduler_data();
    if (esdp) {
	val[0] = (Uint64) esdp->thr_id;
	val[1] = esdp->unique++;
    }
    else {
	val[0] = (Uint64) 0;
	val[1] = (Uint64) erts_atomic64_inc_read_nob(&unique_data.w.val1);
    }
}
Example #7
0
static void send_reply(ErtsMsAcc *msacc, ErtsMSAccReq *msaccrp) {
    ErtsSchedulerData *esdp = erts_get_scheduler_data();
    Process *rp = msaccrp->proc;
    ErtsMessage *msgp = NULL;
    Eterm **hpp, *hp;
    Eterm ref_copy = NIL, msg;
    Uint sz, *szp;
    ErlOffHeap *ohp = NULL;
    ErtsProcLocks rp_locks = (esdp && msaccrp->req_sched == esdp->no
                              ? ERTS_PROC_LOCK_MAIN : 0);

    sz = 0;
    hpp = NULL;
    szp = &sz;

    if (msacc->unmanaged) erts_mtx_lock(&msacc->mtx);

    while (1) {
	if (hpp)
            ref_copy = STORE_NC(hpp, ohp, msaccrp->ref);
	else
            *szp += REF_THING_SIZE;

	if (msaccrp->action != ERTS_MSACC_GATHER)
            msg = ref_copy;
	else {
            msg = erts_msacc_gather_stats(msacc, hpp, szp);
            msg = erts_bld_tuple(hpp, szp, 2, ref_copy, msg);
	}
	if (hpp)
            break;

	msgp = erts_alloc_message_heap(rp, &rp_locks, sz, &hp, &ohp);
        hpp = &hp;
	szp = NULL;
    }

    if (msacc->unmanaged) erts_mtx_unlock(&msacc->mtx);

    erts_queue_message(rp, rp_locks, msgp, msg, am_system);

    if (esdp && msaccrp->req_sched == esdp->no)
	rp_locks &= ~ERTS_PROC_LOCK_MAIN;

    if (rp_locks)
	erts_smp_proc_unlock(rp, rp_locks);

}
Example #8
0
File: erl_msacc.c Project: hawk/otp
static void send_reply(ErtsMsAcc *msacc, ErtsMSAccReq *msaccrp) {
    ErtsSchedulerData *esdp = erts_get_scheduler_data();
    Process *rp = msaccrp->proc;
    ErtsMessage *msgp = NULL;
    Eterm *hp;
    Eterm ref_copy = NIL, msg;
    ErtsProcLocks rp_locks = (esdp && msaccrp->req_sched == esdp->no
                              ? ERTS_PROC_LOCK_MAIN : 0);
    ErtsHeapFactory factory;

    if (msaccrp->action == ERTS_MSACC_GATHER) {

        msgp = erts_factory_message_create(&factory, rp, &rp_locks, DEFAULT_MSACC_MSG_SIZE);

        if (msacc->unmanaged) erts_mtx_lock(&msacc->mtx);

        hp = erts_produce_heap(&factory, REF_THING_SIZE + 3 /* tuple */, 0);
        ref_copy = STORE_NC(&hp, &msgp->hfrag.off_heap, msaccrp->ref);
        msg = erts_msacc_gather_stats(msacc, &factory);
        msg = TUPLE2(hp, ref_copy, msg);

        if (msacc->unmanaged) erts_mtx_unlock(&msacc->mtx);

        erts_factory_close(&factory);
    } else {
        ErlOffHeap *ohp = NULL;
        msgp = erts_alloc_message_heap(rp, &rp_locks, REF_THING_SIZE, &hp, &ohp);
        msg = STORE_NC(&hp, &msgp->hfrag.off_heap, msaccrp->ref);
    }

    erts_queue_message(rp, rp_locks, msgp, msg, am_system);

    if (esdp && msaccrp->req_sched == esdp->no)
	rp_locks &= ~ERTS_PROC_LOCK_MAIN;

    if (rp_locks)
	erts_smp_proc_unlock(rp, rp_locks);

}
Example #9
0
int
erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
{
    int port_was_enqueued = 0;
    Port *pp;
    ErtsPortTaskQueue *ptqp;
    ErtsPortTask *ptp;
    int res = 0;
    int reds = ERTS_PORT_REDS_EXECUTE;
    erts_aint_t io_tasks_executed = 0;
    int fpe_was_unmasked;
    ErtsPortTaskExeBlockData blk_data = {runq, NULL};

    ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq));

    ERTS_PT_CHK_PORTQ(runq);

    pp = pop_port(runq);
    if (!pp) {
	res = 0;
	goto done;
    }

    ERTS_PORT_NOT_IN_RUNQ(pp);

    *curr_port_pp = pp;

    ASSERT(pp->sched.taskq);
    ASSERT(pp->sched.taskq->first);
    ptqp = pp->sched.taskq;
    pp->sched.taskq = NULL;

    ASSERT(!pp->sched.exe_taskq);
    pp->sched.exe_taskq = ptqp;

    if (erts_smp_port_trylock(pp) == EBUSY) {
	erts_smp_runq_unlock(runq);
	erts_smp_port_lock(pp);
	erts_smp_runq_lock(runq);
    }
    
    if (erts_sched_stat.enabled) {
	ErtsSchedulerData *esdp = erts_get_scheduler_data();
	Uint old = ERTS_PORT_SCHED_ID(pp, esdp->no);
	int migrated = old && old != esdp->no;

	erts_smp_spin_lock(&erts_sched_stat.lock);
	erts_sched_stat.prio[ERTS_PORT_PRIO_LEVEL].total_executed++;
	erts_sched_stat.prio[ERTS_PORT_PRIO_LEVEL].executed++;
	if (migrated) {
	    erts_sched_stat.prio[ERTS_PORT_PRIO_LEVEL].total_migrated++;
	    erts_sched_stat.prio[ERTS_PORT_PRIO_LEVEL].migrated++;
	}
	erts_smp_spin_unlock(&erts_sched_stat.lock);
    }

    /* trace port scheduling, in */
    if (IS_TRACED_FL(pp, F_TRACE_SCHED_PORTS)) {
	trace_sched_ports(pp, am_in);
    }

    ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));

    ERTS_PT_CHK_PRES_PORTQ(runq, pp);
    ptp = pop_task(ptqp);

    fpe_was_unmasked = erts_block_fpe();

    while (ptp) {
	ASSERT(pp->sched.taskq != pp->sched.exe_taskq);

	reset_handle(ptp);
	erts_smp_runq_unlock(runq);

	ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
	ERTS_SMP_CHK_NO_PROC_LOCKS;
	ASSERT(pp->drv_ptr);

	switch (ptp->type) {
	case ERTS_PORT_TASK_FREE: /* May be pushed in q at any time */
	    reds += ERTS_PORT_REDS_FREE;
	    erts_smp_runq_lock(runq);

	    erts_unblock_fpe(fpe_was_unmasked);
	    ASSERT(pp->status & ERTS_PORT_SFLG_FREE_SCHEDULED);
	    if (ptqp->first || (pp->sched.taskq && pp->sched.taskq->first))
		handle_remaining_tasks(runq, pp);
	    ASSERT(!ptqp->first
		   && (!pp->sched.taskq || !pp->sched.taskq->first));
#ifdef ERTS_SMP
	    erts_smp_atomic_dec_nob(&pp->refc); /* Not alive */
	    ERTS_SMP_LC_ASSERT(erts_smp_atomic_read_nob(&pp->refc) > 0); /* Lock */
#else
	    erts_port_status_bor_set(pp, ERTS_PORT_SFLG_FREE);	    
#endif

	    port_task_free(ptp);
	    if (pp->sched.taskq)
		port_taskq_free(pp->sched.taskq);
	    pp->sched.taskq = NULL;

	    goto tasks_done;
	case ERTS_PORT_TASK_TIMEOUT:
	    reds += ERTS_PORT_REDS_TIMEOUT;
	    if (!(pp->status & ERTS_PORT_SFLGS_DEAD))
		(*pp->drv_ptr->timeout)((ErlDrvData) pp->drv_data);
	    break;
	case ERTS_PORT_TASK_INPUT:
	    reds += ERTS_PORT_REDS_INPUT;
	    ASSERT((pp->status & ERTS_PORT_SFLGS_DEAD) == 0);
	    /* NOTE some windows drivers use ->ready_input for input and output */
	    (*pp->drv_ptr->ready_input)((ErlDrvData) pp->drv_data, ptp->event);
	    io_tasks_executed++;
	    break;
	case ERTS_PORT_TASK_OUTPUT:
	    reds += ERTS_PORT_REDS_OUTPUT;
	    ASSERT((pp->status & ERTS_PORT_SFLGS_DEAD) == 0);
	    (*pp->drv_ptr->ready_output)((ErlDrvData) pp->drv_data, ptp->event);
	    io_tasks_executed++;
	    break;
	case ERTS_PORT_TASK_EVENT:
	    reds += ERTS_PORT_REDS_EVENT;
	    ASSERT((pp->status & ERTS_PORT_SFLGS_DEAD) == 0);
	    (*pp->drv_ptr->event)((ErlDrvData) pp->drv_data, ptp->event, ptp->event_data);
	    io_tasks_executed++;
	    break;
	case ERTS_PORT_TASK_DIST_CMD:
	    reds += erts_dist_command(pp, CONTEXT_REDS-reds);
	    break;
	default:
	    erl_exit(ERTS_ABORT_EXIT,
		     "Invalid port task type: %d\n",
		     (int) ptp->type);
	    break;
	}

	if ((pp->status & ERTS_PORT_SFLG_CLOSING)
	    && erts_is_port_ioq_empty(pp)) {
	    reds += ERTS_PORT_REDS_TERMINATE;
	    erts_terminate_port(pp);
	}

	ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));

#ifdef ERTS_SMP
	if (pp->xports)
	    erts_smp_xports_unlock(pp);
	ASSERT(!pp->xports);
#endif

	ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));

	port_task_free(ptp);

	erts_smp_runq_lock(runq);

	ptp = pop_task(ptqp);
    }

 tasks_done:

    erts_unblock_fpe(fpe_was_unmasked);

    if (io_tasks_executed) {
	ASSERT(erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks)
	       >= io_tasks_executed);
	erts_smp_atomic_add_relb(&erts_port_task_outstanding_io_tasks,
				 -1*io_tasks_executed);
    }

    *curr_port_pp = NULL;

#ifdef ERTS_SMP
    ASSERT(runq == (ErtsRunQueue *) erts_smp_atomic_read_nob(&pp->run_queue));
#endif

    if (!pp->sched.taskq) {
	ASSERT(pp->sched.exe_taskq);
	pp->sched.exe_taskq = NULL;
    }
    else {
#ifdef ERTS_SMP
	ErtsRunQueue *xrunq;
#endif

	ASSERT(!(pp->status & ERTS_PORT_SFLGS_DEAD));
	ASSERT(pp->sched.taskq->first);

#ifdef ERTS_SMP
	xrunq = erts_check_emigration_need(runq, ERTS_PORT_PRIO_LEVEL);
	if (!xrunq) {
#endif
	    enqueue_port(runq, pp);
	    ASSERT(pp->sched.exe_taskq);
	    pp->sched.exe_taskq = NULL;
	    /* No need to notify ourselves about inc in runq. */
#ifdef ERTS_SMP
	}
	else {
	    /* Port emigrated ... */
	    erts_smp_atomic_set_nob(&pp->run_queue, (erts_aint_t) xrunq);
	    enqueue_port(xrunq, pp);
	    ASSERT(pp->sched.exe_taskq);
	    pp->sched.exe_taskq = NULL;
	    erts_smp_runq_unlock(xrunq);
	    erts_smp_notify_inc_runq(xrunq);
	}
#endif
	port_was_enqueued = 1;
    }

    res = (erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks)
	   != (erts_aint_t) 0);

    ERTS_PT_CHK_PRES_PORTQ(runq, pp);

    port_taskq_free(ptqp);

    if (erts_system_profile_flags.runnable_ports && (port_was_enqueued != 1)) {
    	profile_runnable_port(pp, am_inactive);
    }

    /* trace port scheduling, out */
    if (IS_TRACED_FL(pp, F_TRACE_SCHED_PORTS)) {
    	trace_sched_ports(pp, am_out);
    }
#ifndef ERTS_SMP
    erts_port_release(pp);
#else
    {
	erts_aint_t refc;
	erts_smp_mtx_unlock(pp->lock);
	refc = erts_smp_atomic_dec_read_nob(&pp->refc);
	ASSERT(refc >= 0);
	if (refc == 0) {
	    erts_smp_runq_unlock(runq);
	    erts_port_cleanup(pp); /* Might aquire runq lock */
	    erts_smp_runq_lock(runq);
	    res = (erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks)
		   != (erts_aint_t) 0);
	}
    }
#endif

 done:
    blk_data.resp = &res;

    ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq));

    ERTS_PORT_REDUCTIONS_EXECUTED(runq, reds);

    return res;
}
Example #10
0
void
erl_start(int argc, char **argv)
{
    int i = 1;
    char* arg=NULL;
    char* Parg = NULL;
    int have_break_handler = 1;
    char envbuf[21]; /* enough for any 64-bit integer */
    size_t envbufsz;
    int ncpu = early_init(&argc, argv);

    envbufsz = sizeof(envbuf);
    if (erts_sys_getenv(ERL_MAX_ETS_TABLES_ENV, envbuf, &envbufsz) == 0)
	user_requested_db_max_tabs = atoi(envbuf);
    else
	user_requested_db_max_tabs = 0;

    envbufsz = sizeof(envbuf);
    if (erts_sys_getenv("ERL_FULLSWEEP_AFTER", envbuf, &envbufsz) == 0) {
	Uint16 max_gen_gcs = atoi(envbuf);
	erts_smp_atomic32_set_nob(&erts_max_gen_gcs,
				  (erts_aint32_t) max_gen_gcs);
    }

#if (defined(__APPLE__) && defined(__MACH__)) || defined(__DARWIN__)
    /*
     * The default stack size on MacOS X is too small for pcre.
     */
    erts_sched_thread_suggested_stack_size = 256;
#endif

#ifdef DEBUG
    verbose = DEBUG_DEFAULT;
#endif

    erts_error_logger_warnings = am_error;

    while (i < argc) {
	if (argv[i][0] != '-') {
	    erts_usage();
	}
	if (strcmp(argv[i], "--") == 0) { /* end of emulator options */
	    i++;
	    break;
	}
	switch (argv[i][1]) {

	    /*
	     * NOTE: -M flags are handled (and removed from argv) by
	     * erts_alloc_init(). 
	     *
	     * The -d, -m, -S, -t, and -T flags was removed in
	     * Erlang 5.3/OTP R9C.
	     *
	     * -S, and -T has been reused in Erlang 5.5/OTP R11B.
	     *
	     * -d has been reused in a patch R12B-4.
	     */

	case '#' :
	    arg = get_arg(argv[i]+2, argv[i+1], &i);
	    if ((display_items = atoi(arg)) == 0) {
		erts_fprintf(stderr, "bad display items%s\n", arg);
		erts_usage();
	    }
	    VERBOSE(DEBUG_SYSTEM,
                    ("using display items %d\n",display_items));
	    break;
	case 'f':
	    if (!strncmp(argv[i],"-fn",3)) {
		arg = get_arg(argv[i]+3, argv[i+1], &i);
		switch (*arg) {
		case 'u':
		    erts_set_user_requested_filename_encoding(ERL_FILENAME_UTF8);
		    break;
		case 'l':
		    erts_set_user_requested_filename_encoding(ERL_FILENAME_LATIN1);
		    break;
		case 'a':
		    erts_set_user_requested_filename_encoding(ERL_FILENAME_UNKNOWN);
		default:
		    erts_fprintf(stderr, "bad filename encoding %s, can be (l,u or a)\n", arg);
		    erts_usage();
		}
		break;
	    } else {
		erts_fprintf(stderr, "%s unknown flag %s\n", argv[0], argv[i]);
		erts_usage();
	    }
	case 'L':
	    erts_no_line_info = 1;
	    break;
	case 'v':
#ifdef DEBUG
	    if (argv[i][2] == '\0') {
		verbose |= DEBUG_SYSTEM;
	    } else {
		char *ch;
		for (ch = argv[i]+2; *ch != '\0'; ch++) {
		    switch (*ch) {
		    case 's': verbose |= DEBUG_SYSTEM; break;
		    case 'g': verbose |= DEBUG_PRIVATE_GC; break;
		    case 'M': verbose |= DEBUG_MEMORY; break;
		    case 'a': verbose |= DEBUG_ALLOCATION; break;
		    case 't': verbose |= DEBUG_THREADS; break;
		    case 'p': verbose |= DEBUG_PROCESSES; break;
		    case 'm': verbose |= DEBUG_MESSAGES; break;
		    default : erts_fprintf(stderr,"Unknown verbose option: %c\n",*ch);
		    }
		}
	    }
            erts_printf("Verbose level: ");
            if (verbose & DEBUG_SYSTEM) erts_printf("SYSTEM ");
            if (verbose & DEBUG_PRIVATE_GC) erts_printf("PRIVATE_GC ");
            if (verbose & DEBUG_MEMORY) erts_printf("PARANOID_MEMORY ");
	    if (verbose & DEBUG_ALLOCATION) erts_printf("ALLOCATION ");
	    if (verbose & DEBUG_THREADS) erts_printf("THREADS ");
	    if (verbose & DEBUG_PROCESSES) erts_printf("PROCESSES ");
	    if (verbose & DEBUG_MESSAGES) erts_printf("MESSAGES ");
            erts_printf("\n");
#else
	    erts_fprintf(stderr, "warning: -v (only in debug compiled code)\n");
#endif
	    break;
	case 'V' :
	    {
		char tmp[256];

		tmp[0] = tmp[1] = '\0';
#ifdef DEBUG
		strcat(tmp, ",DEBUG");
#endif
#ifdef ERTS_SMP
		strcat(tmp, ",SMP");
#endif
#ifdef USE_THREADS
		strcat(tmp, ",ASYNC_THREADS");
#endif
#ifdef HIPE
		strcat(tmp, ",HIPE");
#endif
		erts_fprintf(stderr, "Erlang ");
		if (tmp[1]) {
		    erts_fprintf(stderr, "(%s) ", tmp+1);
		}
		erts_fprintf(stderr, "(" EMULATOR ") emulator version "
			   ERLANG_VERSION "\n");
		erl_exit(0, "");
	    }
	    break;

	case 'H':		/* undocumented */
	    fprintf(stderr, "The undocumented +H option has been removed (R10B-6).\n\n");
	    break;

	case 'h': {
	    char *sub_param = argv[i]+2;
	    /* set default heap size
	     *
	     * h|ms  - min_heap_size
	     * h|mbs - min_bin_vheap_size
	     *
	     */
	    if (has_prefix("mbs", sub_param)) {
		arg = get_arg(sub_param+3, argv[i+1], &i);
		if ((BIN_VH_MIN_SIZE = atoi(arg)) <= 0) {
		    erts_fprintf(stderr, "bad heap size %s\n", arg);
		    erts_usage();
		}
		VERBOSE(DEBUG_SYSTEM, ("using minimum binary virtual heap size %d\n", BIN_VH_MIN_SIZE));

	    } else if (has_prefix("ms", sub_param)) {
		arg = get_arg(sub_param+2, argv[i+1], &i);
		if ((H_MIN_SIZE = atoi(arg)) <= 0) {
		    erts_fprintf(stderr, "bad heap size %s\n", arg);
		    erts_usage();
		}
		VERBOSE(DEBUG_SYSTEM, ("using minimum heap size %d\n", H_MIN_SIZE));
	    } else {
	        /* backward compatibility */
		arg = get_arg(argv[i]+2, argv[i+1], &i);
		if ((H_MIN_SIZE = atoi(arg)) <= 0) {
		    erts_fprintf(stderr, "bad heap size %s\n", arg);
		    erts_usage();
		}
		VERBOSE(DEBUG_SYSTEM, ("using minimum heap size %d\n", H_MIN_SIZE));
	    }
	    break;
	}
	case 'd':
	    /*
	     * Never produce crash dumps for internally detected
	     * errors; only produce a core dump. (Generation of
	     * crash dumps is destructive and makes it impossible
	     * to inspect the contents of process heaps in the
	     * core dump.)
	     */
	    erts_no_crash_dump = 1;
	    break;

	case 'e':
	    if (sys_strcmp("c", argv[i]+2) == 0) {
		erts_ets_always_compress = 1;
	    }
	    else {
		/* set maximum number of ets tables */
		arg = get_arg(argv[i]+2, argv[i+1], &i);
		if (( user_requested_db_max_tabs = atoi(arg) ) < 0) {
		    erts_fprintf(stderr, "bad maximum number of ets tables %s\n", arg);
		    erts_usage();
		}
		VERBOSE(DEBUG_SYSTEM,
			("using maximum number of ets tables %d\n",
			 user_requested_db_max_tabs));
	    }
	    break;

	case 'i':
	    /* define name of module for initial function */
	    init = get_arg(argv[i]+2, argv[i+1], &i);
	    break;

	case 'b':
	    /* define name of initial function */
	    boot = get_arg(argv[i]+2, argv[i+1], &i);
	    break;

	case 'B':
	  if (argv[i][2] == 'i')          /* +Bi */
	    ignore_break = 1;
	  else if (argv[i][2] == 'c')     /* +Bc */
	    replace_intr = 1;
	  else if (argv[i][2] == 'd')     /* +Bd */
	    have_break_handler = 0;
	  else if (argv[i+1][0] == 'i') { /* +B i */
	    get_arg(argv[i]+2, argv[i+1], &i);
	    ignore_break = 1;
	  }
	  else if (argv[i+1][0] == 'c') { /* +B c */
	    get_arg(argv[i]+2, argv[i+1], &i);
	    replace_intr = 1;
	  }
	  else if (argv[i+1][0] == 'd') { /* +B d */
	    get_arg(argv[i]+2, argv[i+1], &i);
	    have_break_handler = 0;
	  }
	  else			          /* +B */
	    have_break_handler = 0;
	  break;

	case 'K':
	    /* If kernel poll support is present,
	       erl_sys_args() will remove the K parameter
	       and value */
	    get_arg(argv[i]+2, argv[i+1], &i);
	    erts_fprintf(stderr,
		       "kernel-poll not supported; \"K\" parameter ignored\n",
		       arg);
	    break;

	case 'P':
	    /* set maximum number of processes */
	    Parg = get_arg(argv[i]+2, argv[i+1], &i);
	    erts_proc.max = atoi(Parg);
	    /* Check of result is delayed until later. This is because +R
	       may be given after +P. */
	    break;

	case 'S' : /* Was handled in early_init() just read past it */
	    (void) get_arg(argv[i]+2, argv[i+1], &i);
	    break;

	case 's' : {
	    char *estr;
	    int res;
	    char *sub_param = argv[i]+2;
	    if (has_prefix("bt", sub_param)) {
		arg = get_arg(sub_param+2, argv[i+1], &i);
		res = erts_init_scheduler_bind_type_string(arg);
		if (res != ERTS_INIT_SCHED_BIND_TYPE_SUCCESS) {
		    switch (res) {
		    case ERTS_INIT_SCHED_BIND_TYPE_NOT_SUPPORTED:
			estr = "not supported";
			break;
		    case ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_CPU_TOPOLOGY:
			estr = "no cpu topology available";
			break;
		    case ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_BAD_TYPE:
			estr = "invalid type";
			break;
		    default:
			estr = "undefined error";
			break;
		    }
		    erts_fprintf(stderr,
				 "setting scheduler bind type '%s' failed: %s\n",
				 arg,
				 estr);
		    erts_usage();
		}
	    }
	    else if (has_prefix("bwt", sub_param)) {
		arg = get_arg(sub_param+3, argv[i+1], &i);
		if (erts_sched_set_busy_wait_threshold(arg) != 0) {
		    erts_fprintf(stderr, "bad scheduler busy wait threshold: %s\n",
				 arg);
		    erts_usage();
		}
		VERBOSE(DEBUG_SYSTEM,
			("scheduler wakup threshold: %s\n", arg));
	    }
	    else if (has_prefix("cl", sub_param)) {
		arg = get_arg(sub_param+2, argv[i+1], &i);
		if (sys_strcmp("true", arg) == 0)
		    erts_sched_compact_load = 1;
		else if (sys_strcmp("false", arg) == 0)
		    erts_sched_compact_load = 0;
		else {
		    erts_fprintf(stderr,
				 "bad scheduler compact load value '%s'\n",
				 arg);
		    erts_usage();
		}
	    }
	    else if (has_prefix("ct", sub_param)) {
		arg = get_arg(sub_param+2, argv[i+1], &i);
		res = erts_init_cpu_topology_string(arg);
		if (res != ERTS_INIT_CPU_TOPOLOGY_OK) {
		    switch (res) {
		    case ERTS_INIT_CPU_TOPOLOGY_INVALID_ID:
			estr = "invalid identifier";
			break;
		    case ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE:
			estr = "invalid identifier range";
			break;
		    case ERTS_INIT_CPU_TOPOLOGY_INVALID_HIERARCHY:
			estr = "invalid hierarchy";
			break;
		    case ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_TYPE:
			estr = "invalid identifier type";
			break;
		    case ERTS_INIT_CPU_TOPOLOGY_INVALID_NODES:
			estr = "invalid nodes declaration";
			break;
		    case ERTS_INIT_CPU_TOPOLOGY_MISSING_LID:
			estr = "missing logical identifier";
			break;
		    case ERTS_INIT_CPU_TOPOLOGY_NOT_UNIQUE_LIDS:
			estr = "not unique logical identifiers";
			break;
		    case ERTS_INIT_CPU_TOPOLOGY_NOT_UNIQUE_ENTITIES:
			estr = "not unique entities";
			break;
		    case ERTS_INIT_CPU_TOPOLOGY_MISSING:
			estr = "missing cpu topology";
			break;
		    default:
			estr = "undefined error";
			break;
		    }
		    erts_fprintf(stderr,
				 "bad cpu topology '%s': %s\n",
				 arg,
				 estr);
		    erts_usage();
		}
	    }
	    else if (sys_strcmp("nsp", sub_param) == 0)
		erts_use_sender_punish = 0;
	    else if (sys_strcmp("wt", sub_param) == 0) {
		arg = get_arg(sub_param+2, argv[i+1], &i);
		if (erts_sched_set_wakeup_other_thresold(arg) != 0) {
		    erts_fprintf(stderr, "scheduler wakeup threshold: %s\n",
				 arg);
		    erts_usage();
		}
		VERBOSE(DEBUG_SYSTEM,
			("scheduler wakeup threshold: %s\n", arg));
	    }
	    else if (sys_strcmp("ws", sub_param) == 0) {
		arg = get_arg(sub_param+2, argv[i+1], &i);
		if (erts_sched_set_wakeup_other_type(arg) != 0) {
		    erts_fprintf(stderr, "scheduler wakeup strategy: %s\n",
				 arg);
		    erts_usage();
		}
		VERBOSE(DEBUG_SYSTEM,
			("scheduler wakeup threshold: %s\n", arg));
	    }
	    else if (has_prefix("ss", sub_param)) {
		/* suggested stack size (Kilo Words) for scheduler threads */
		arg = get_arg(sub_param+2, argv[i+1], &i);
		erts_sched_thread_suggested_stack_size = atoi(arg);

		if ((erts_sched_thread_suggested_stack_size
		     < ERTS_SCHED_THREAD_MIN_STACK_SIZE)
		    || (erts_sched_thread_suggested_stack_size >
			ERTS_SCHED_THREAD_MAX_STACK_SIZE)) {
		    erts_fprintf(stderr, "bad stack size for scheduler threads %s\n",
				 arg);
		    erts_usage();
		}
		VERBOSE(DEBUG_SYSTEM,
			("suggested scheduler thread stack size %d kilo words\n",
			 erts_sched_thread_suggested_stack_size));
	    }
	    else {
		erts_fprintf(stderr, "bad scheduling option %s\n", argv[i]);
		erts_usage();
	    }
	    break;
	}
	case 't':
	    /* set atom table size */
	    arg = get_arg(argv[i]+2, argv[i+1], &i);
	    errno = 0;
	    erts_atom_table_size = strtol(arg, NULL, 10);
	    if (errno != 0 ||
		erts_atom_table_size < MIN_ATOM_TABLE_SIZE ||
		erts_atom_table_size > MAX_ATOM_TABLE_SIZE) {
		erts_fprintf(stderr, "bad atom table size %s\n", arg);
		erts_usage();
	    }
	    VERBOSE(DEBUG_SYSTEM,
                    ("setting maximum number of atoms to %d\n",
		     erts_atom_table_size));
	    break;

	case 'T' :
	    arg = get_arg(argv[i]+2, argv[i+1], &i);
	    errno = 0;
	    erts_modified_timing_level = atoi(arg);
	    if ((erts_modified_timing_level == 0 && errno != 0)
		|| erts_modified_timing_level < 0
		|| erts_modified_timing_level >= ERTS_MODIFIED_TIMING_LEVELS) {
		erts_fprintf(stderr, "bad modified timing level %s\n", arg);
		erts_usage();
	    }
	    else {
		VERBOSE(DEBUG_SYSTEM,
			("using modified timing level %d\n",
			 erts_modified_timing_level));
	    }

	    break;

	case 'R': {
	    /* set compatibility release */

	    arg = get_arg(argv[i]+2, argv[i+1], &i);
	    erts_compat_rel = atoi(arg);

	    if (erts_compat_rel < ERTS_MIN_COMPAT_REL
		|| erts_compat_rel > this_rel_num()) {
		erts_fprintf(stderr, "bad compatibility release number %s\n", arg);
		erts_usage();
	    }

	    ASSERT(ERTS_MIN_COMPAT_REL >= 7);
	    switch (erts_compat_rel) {
	    case 7:
	    case 8:
	    case 9:
		erts_use_r9_pids_ports = 1;
	    default:
		break;
	    }

	    break;
	}

	case 'A': /* Was handled in early init just read past it */
	    (void) get_arg(argv[i]+2, argv[i+1], &i);
	    break;

	case 'a':
	    /* suggested stack size (Kilo Words) for threads in thread pool */
	    arg = get_arg(argv[i]+2, argv[i+1], &i);
	    erts_async_thread_suggested_stack_size = atoi(arg);
	    
	    if ((erts_async_thread_suggested_stack_size
		 < ERTS_ASYNC_THREAD_MIN_STACK_SIZE)
		|| (erts_async_thread_suggested_stack_size >
		    ERTS_ASYNC_THREAD_MAX_STACK_SIZE)) {
		erts_fprintf(stderr, "bad stack size for async threads %s\n",
			     arg);
		erts_usage();
	    }

	    VERBOSE(DEBUG_SYSTEM,
		    ("suggested async-thread stack size %d kilo words\n",
		     erts_async_thread_suggested_stack_size));
	    break;

	case 'r': {
	    char *sub_param = argv[i]+2;
	    if (has_prefix("g", sub_param)) {
		get_arg(sub_param+1, argv[i+1], &i);
		/* already handled */
	    }
	    else {
		erts_ets_realloc_always_moves = 1;
	    }
	    break;
	}
	case 'n':   /* XXX obsolete */
	    break;
	case 'c':
	    if (argv[i][2] == 0) { /* -c: documented option */
		erts_disable_tolerant_timeofday = 1;
	    }
#ifdef ERTS_OPCODE_COUNTER_SUPPORT
	    else if (argv[i][2] == 'i') { /* -ci: undcoumented option*/
		count_instructions = 1;
	    }
#endif
	    break;
	case 'W':
	    arg = get_arg(argv[i]+2, argv[i+1], &i);
	    switch (arg[0]) {
	    case 'i':
		erts_error_logger_warnings = am_info;
		break;
	    case 'w':
		erts_error_logger_warnings = am_warning;
		break;
	    case 'e': /* The default */
		erts_error_logger_warnings = am_error;
	    default:
		erts_fprintf(stderr, "unrecognized warning_map option %s\n", arg);
		erts_usage();
	    }
	    break;

	case 'z': {
	    char *sub_param = argv[i]+2;
	    int new_limit;

	    if (has_prefix("dbbl", sub_param)) {
		arg = get_arg(sub_param+4, argv[i+1], &i);
		new_limit = atoi(arg);
		if (new_limit < 1 || INT_MAX/1024 < new_limit) {
		    erts_fprintf(stderr, "Invalid dbbl limit: %d\n", new_limit);
		    erts_usage();
		} else {
		    erts_dist_buf_busy_limit = new_limit*1024;
		}
	    } else {
		erts_fprintf(stderr, "bad -z option %s\n", argv[i]);
		erts_usage();
	    }
	    break;
        }

	default:
	    erts_fprintf(stderr, "%s unknown flag %s\n", argv[0], argv[i]);
	    erts_usage();
	}
	i++;
    }

    /* Delayed check of +P flag */
    if (erts_proc.max < ERTS_MIN_PROCESSES
	|| erts_proc.max > ERTS_MAX_PROCESSES
	|| (erts_use_r9_pids_ports
	    && erts_proc.max > ERTS_MAX_R9_PROCESSES)) {
	erts_fprintf(stderr, "bad number of processes %s\n", Parg);
	erts_usage();
    }

   /* Restart will not reinstall the break handler */
#ifdef __WIN32__
    if (ignore_break)
	erts_set_ignore_break();
    else if (replace_intr)
	erts_replace_intr();
    else
	init_break_handler();
#else
    if (ignore_break)
	erts_set_ignore_break();
    else if (have_break_handler)
	init_break_handler();
    if (replace_intr)
	erts_replace_intr();
#endif

    boot_argc = argc - i;  /* Number of arguments to init */
    boot_argv = &argv[i];

    erl_init(ncpu);

    load_preloaded();
    erts_end_staging_code_ix();
    erts_commit_staging_code_ix();

    erts_initialized = 1;

    erl_first_process_otp("otp_ring0", NULL, 0, boot_argc, boot_argv);

#ifdef ERTS_SMP
    erts_start_schedulers();
    /* Let system specific code decide what to do with the main thread... */

    erts_sys_main_thread(); /* May or may not return! */
#else
    erts_thr_set_main_status(1, 1);
#if ERTS_USE_ASYNC_READY_Q
    erts_get_scheduler_data()->aux_work_data.async_ready.queue
	= erts_get_async_ready_queue(1);
#endif
    set_main_stack_size();
    process_main();
#endif
}
Example #11
0
NifExport *
erts_nif_export_schedule(Process *c_p, Process *dirty_shadow_proc,
			 ErtsCodeMFA *mfa, BeamInstr *pc,
			 BeamInstr instr,
			 void *dfunc, void *ifunc,
			 Eterm mod, Eterm func,
			 int argc, const Eterm *argv)
{
    Process *used_proc;
    ErtsSchedulerData *esdp;
    Eterm* reg;
    NifExport* nep;
    int i;

    ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p)
		       & ERTS_PROC_LOCK_MAIN);

    if (dirty_shadow_proc) {
	esdp = erts_get_scheduler_data();
	ASSERT(esdp && ERTS_SCHEDULER_IS_DIRTY(esdp));

	used_proc = dirty_shadow_proc;
    }
    else {
	esdp = erts_proc_sched_data(c_p);
	ASSERT(esdp && !ERTS_SCHEDULER_IS_DIRTY(esdp));

	used_proc = c_p;
	ERTS_VBUMP_ALL_REDS(c_p);
    }

    reg = esdp->x_reg_array;

    if (mfa)
	nep = erts_get_proc_nif_export(c_p, (int) mfa->arity);
    else {
	/* If no mfa, this is not the first schedule... */
	nep = ERTS_PROC_GET_NIF_TRAP_EXPORT(c_p);
	ASSERT(nep && nep->argc >= 0);
    }

    if (nep->argc < 0) {
	/*
	 * First schedule; save things that might
	 * need to be restored...
	 */
	for (i = 0; i < (int) mfa->arity; i++)
	    nep->argv[i] = reg[i];
	nep->pc = pc;
	nep->cp = c_p->cp;
	nep->mfa = mfa;
	nep->current = c_p->current;
	ASSERT(argc >= 0);
	nep->argc = (int) mfa->arity;
	nep->m = NULL;

	ASSERT(!erts_check_nif_export_in_area(c_p,
					      (char *) nep,
					      (sizeof(NifExport)
					       + (sizeof(Eterm)
						  *(nep->argc-1)))));
    }
    /* Copy new arguments into register array if necessary... */
    if (reg != argv) {
	for (i = 0; i < argc; i++)
	    reg[i] = argv[i];
    }
    ASSERT(is_atom(mod) && is_atom(func));
    nep->exp.info.mfa.module = mod;
    nep->exp.info.mfa.function = func;
    nep->exp.info.mfa.arity = (Uint) argc;
    nep->exp.beam[0] = (BeamInstr) instr; /* call_nif || apply_bif */
    nep->exp.beam[1] = (BeamInstr) dfunc;
    nep->func = ifunc;
    used_proc->arity = argc;
    used_proc->freason = TRAP;
    used_proc->i = (BeamInstr*) nep->exp.addressv[0];
    return nep;
}
Example #12
0
File: break.c Project: easemob/otp
/* XXX THIS SHOULD BE IN SYSTEM !!!! */
void
erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
{
#ifdef ERTS_SMP
    ErtsThrPrgrData tpd_buf; /* in case we aren't a managed thread... */
#endif
    int fd;
    size_t envsz;
    time_t now;
    char env[21]; /* enough to hold any 64-bit integer */
    size_t dumpnamebufsize = MAXPATHLEN;
    char dumpnamebuf[MAXPATHLEN];
    char* dumpname;
    int secs;
    int env_erl_crash_dump_seconds_set = 1;
    int i;

    if (ERTS_SOMEONE_IS_CRASH_DUMPING)
	return;

#ifdef ERTS_SMP
    /* Order all managed threads to block, this has to be done
       first to guarantee that this is the only thread to generate
       crash dump. */
    erts_thr_progress_fatal_error_block(&tpd_buf);

#ifdef ERTS_THR_HAVE_SIG_FUNCS
    /*
     * We suspend all scheduler threads so that we can dump some
     * data about the currently running processes and scheduler data.
     * We have to be very very careful when doing this as the schedulers
     * could be anywhere.
     */
    for (i = 0; i < erts_no_schedulers; i++) {
        erts_tid_t tid = ERTS_SCHEDULER_IX(i)->tid;
        if (!erts_equal_tids(tid,erts_thr_self()))
            sys_thr_suspend(tid);
    }

#endif

    /* Allow us to pass certain places without locking... */
    erts_smp_atomic32_set_mb(&erts_writing_erl_crash_dump, 1);
    erts_smp_tsd_set(erts_is_crash_dumping_key, (void *) 1);

#else /* !ERTS_SMP */
    erts_writing_erl_crash_dump = 1;
#endif /* ERTS_SMP */

    envsz = sizeof(env);
    /* ERL_CRASH_DUMP_SECONDS not set
     * if we have a heart port, break immediately
     * otherwise dump crash indefinitely (until crash is complete)
     * same as ERL_CRASH_DUMP_SECONDS = 0
     * - do not write dump
     * - do not set an alarm
     * - break immediately
     *
     * ERL_CRASH_DUMP_SECONDS = 0
     * - do not write dump
     * - do not set an alarm
     * - break immediately
     *
     * ERL_CRASH_DUMP_SECONDS < 0
     * - do not set alarm
     * - write dump until done
     *
     * ERL_CRASH_DUMP_SECONDS = S (and S positive)
     * - Don't dump file forever
     * - set alarm (set in sys)
     * - write dump until alarm or file is written completely
     */
	
    if (erts_sys_getenv__("ERL_CRASH_DUMP_SECONDS", env, &envsz) != 0) {
	env_erl_crash_dump_seconds_set = 0;
	secs = -1;
    } else {
	env_erl_crash_dump_seconds_set = 1;
	secs = atoi(env);
    }

    if (secs == 0) {
	return;
    }

    /* erts_sys_prepare_crash_dump returns 1 if heart port is found, otherwise 0
     * If we don't find heart (0) and we don't have ERL_CRASH_DUMP_SECONDS set
     * we should continue writing a dump
     *
     * beware: secs -1 means no alarm
     */

    if (erts_sys_prepare_crash_dump(secs) && !env_erl_crash_dump_seconds_set ) {
	return;
    }

    if (erts_sys_getenv__("ERL_CRASH_DUMP",&dumpnamebuf[0],&dumpnamebufsize) != 0)
	dumpname = "erl_crash.dump";
    else
	dumpname = &dumpnamebuf[0];
    
    erts_fprintf(stderr,"\nCrash dump is being written to: %s...", dumpname);

    fd = open(dumpname,O_WRONLY | O_CREAT | O_TRUNC,0640);
    if (fd < 0)
	return; /* Can't create the crash dump, skip it */
    time(&now);
    erts_fdprintf(fd, "=erl_crash_dump:0.3\n%s", ctime(&now));

    if (file != NULL)
       erts_fdprintf(fd, "The error occurred in file %s, line %d\n", file, line);

    if (fmt != NULL && *fmt != '\0') {
	erts_fdprintf(fd, "Slogan: ");
	erts_vfdprintf(fd, fmt, args);
    }
    erts_fdprintf(fd, "System version: ");
    erts_print_system_version(fd, NULL, NULL);
    erts_fdprintf(fd, "%s\n", "Compiled: " ERLANG_COMPILE_DATE);

    erts_fdprintf(fd, "Taints: ");
    erts_print_nif_taints(fd, NULL);
    erts_fdprintf(fd, "Atoms: %d\n", atom_table_size());

#ifdef USE_THREADS
    /* We want to note which thread it was that called erl_exit */
    if (erts_get_scheduler_data()) {
        erts_fdprintf(fd, "Calling Thread: scheduler:%d\n",
                      erts_get_scheduler_data()->no);
    } else {
        if (!erts_thr_getname(erts_thr_self(), dumpnamebuf, MAXPATHLEN))
            erts_fdprintf(fd, "Calling Thread: %s\n", dumpnamebuf);
        else
            erts_fdprintf(fd, "Calling Thread: %p\n", erts_thr_self());
    }
#else
    erts_fdprintf(fd, "Calling Thread: scheduler:1\n");
#endif

#if defined(ERTS_HAVE_TRY_CATCH)

    /*
     * erts_print_scheduler_info is not guaranteed to be safe to call
     * here for all schedulers as we may have suspended a scheduler
     * in the middle of updating the STACK_TOP and STACK_START
     * variables and thus when scanning the stack we could get
     * segmentation faults. We protect against this very unlikely
     * scenario by using the ERTS_SYS_TRY_CATCH.
     */
    for (i = 0; i < erts_no_schedulers; i++) {
        ERTS_SYS_TRY_CATCH(
            erts_print_scheduler_info(fd, NULL, ERTS_SCHEDULER_IX(i)),
            erts_fdprintf(fd, "** crashed **\n"));
    }
#endif

#ifdef ERTS_SMP

#if defined(ERTS_THR_HAVE_SIG_FUNCS)

    /* We resume all schedulers so that we are in a known safe state
       when we write the rest of the crash dump */
    for (i = 0; i < erts_no_schedulers; i++) {
        erts_tid_t tid = ERTS_SCHEDULER_IX(i)->tid;
        if (!erts_equal_tids(tid,erts_thr_self()))
	    sys_thr_resume(tid);
    }
#endif

    /*
     * Wait for all managed threads to block. If all threads haven't blocked
     * after a minute, we go anyway and hope for the best...
     *
     * We do not release system again. We expect an exit() or abort() after
     * dump has been written.
     */
    erts_thr_progress_fatal_error_wait(60000);
    /* Either worked or not... */
#endif

#ifndef ERTS_HAVE_TRY_CATCH
    /* This is safe to call here, as all schedulers are blocked */
    for (i = 0; i < erts_no_schedulers; i++) {
        erts_print_scheduler_info(fd, NULL, ERTS_SCHEDULER_IX(i));
    }
#endif
    
    info(fd, NULL); /* General system info */
    if (erts_ptab_initialized(&erts_proc))
	process_info(fd, NULL); /* Info about each process and port */
    db_info(fd, NULL, 0);
    erts_print_bif_timer_info(fd, NULL);
    distribution_info(fd, NULL);
    erts_fdprintf(fd, "=loaded_modules\n");
    loaded(fd, NULL);
    erts_dump_fun_entries(fd, NULL);
    erts_deep_process_dump(fd, NULL);
    erts_fdprintf(fd, "=atoms\n");
    dump_atoms(fd, NULL);

    /* Keep the instrumentation data at the end of the dump */
    if (erts_instr_memory_map || erts_instr_stat) {
	erts_fdprintf(fd, "=instr_data\n");

	if (erts_instr_stat) {
	    erts_fdprintf(fd, "=memory_status\n");
	    erts_instr_dump_stat_to_fd(fd, 0);
	}
	if (erts_instr_memory_map) {
	    erts_fdprintf(fd, "=memory_map\n");
	    erts_instr_dump_memory_map_to_fd(fd);
	}
    }

    erts_fdprintf(fd, "=end\n");
    close(fd);
    erts_fprintf(stderr,"done\n");
}
Example #13
0
/* Add messages last in message queue */
static void
queue_messages(Process* receiver,
               ErtsProcLocks receiver_locks,
               ErtsMessage* first,
               ErtsMessage** last,
               Uint len)
{
    int locked_msgq = 0;
    erts_aint32_t state;

#ifdef DEBUG
    {
        ErtsMessage* fmsg = ERTS_SIG_IS_MSG(first) ? first : first->next;
        ASSERT(fmsg);
        ASSERT(is_value(ERL_MESSAGE_TERM(fmsg)));
        ASSERT(is_value(ERL_MESSAGE_FROM(fmsg)));
        ASSERT(ERL_MESSAGE_TOKEN(fmsg) == am_undefined ||
               ERL_MESSAGE_TOKEN(fmsg) == NIL ||
               is_tuple(ERL_MESSAGE_TOKEN(fmsg)));
    }
#endif

    ERTS_LC_ASSERT((erts_proc_lc_my_proc_locks(receiver) & ERTS_PROC_LOCK_MSGQ)
                   == (receiver_locks & ERTS_PROC_LOCK_MSGQ));

    if (!(receiver_locks & ERTS_PROC_LOCK_MSGQ)) {
        erts_proc_lock(receiver, ERTS_PROC_LOCK_MSGQ);
	locked_msgq = 1;
    }

    state = erts_atomic32_read_nob(&receiver->state);

    if (state & ERTS_PSFLG_EXITING) {
	/* Drop message if receiver is exiting or has a pending exit... */
	if (locked_msgq)
            erts_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ);
        if (ERTS_SIG_IS_NON_MSG(first)) {
            ErtsSchedulerData* esdp = erts_get_scheduler_data();
            ASSERT(esdp);
            ASSERT(!esdp->pending_signal.sig);
            esdp->pending_signal.sig = (ErtsSignal*) first;
            esdp->pending_signal.to = receiver->common.id;
            first = first->next;
        }
	erts_cleanup_messages(first);
        return;
    }

    if (last == &first->next) {
        ASSERT(len == 1);
        LINK_MESSAGE(receiver, first);
    }
    else {
        erts_enqueue_signals(receiver, first, last, NULL, len, state);
    }

    if (receiver_locks & ERTS_PROC_LOCK_MAIN)
        erts_proc_sig_fetch(receiver);

    if (locked_msgq) {
	erts_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ);
    }

    if (last == &first->next)
        erts_proc_notify_new_message(receiver, receiver_locks);
    else
        erts_proc_notify_new_sig(receiver, state, ERTS_PSFLG_ACTIVE);
}