示例#1
0
void
smp_rendezvous_cpus(cpuset_t map,
	void (*setup_func)(void *), 
	void (*action_func)(void *),
	void (*teardown_func)(void *),
	void *arg)
{
	/*
	 * In the !SMP case we just need to ensure the same initial conditions
	 * as the SMP case.
	 */
	spinlock_enter();
	if (setup_func != NULL)
		setup_func(arg);
	if (action_func != NULL)
		action_func(arg);
	if (teardown_func != NULL)
		teardown_func(arg);
	spinlock_exit();
}
示例#2
0
static void
i8259_init(struct atpic *pic, int slave)
{
	int imr_addr;

	/* Reset the PIC and program with next four bytes. */
	spinlock_enter();
	outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;

	/* Start vector. */
	outb(imr_addr, pic->at_intbase);

	/*
	 * Setup slave links.  For the master pic, indicate what line
	 * the slave is configured on.  For the slave indicate
	 * which line on the master we are connected to.
	 */
	if (slave)
		outb(imr_addr, ICU_SLAVEID);
	else
		outb(imr_addr, IRQ_MASK(ICU_SLAVEID));

	/* Set mode. */
	if (slave)
		outb(imr_addr, SLAVE_MODE);
	else
		outb(imr_addr, MASTER_MODE);

	/* Set interrupt enable mask. */
	outb(imr_addr, pic->at_imen);

	/* Reset is finished, default to IRR on read. */
	outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);

	/* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
	if (!slave)
		outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);

	spinlock_exit();
}
示例#3
0
void
__mtx_lock_spin_flags(volatile uintptr_t *c, int opts, const char *file,
    int line)
{
	struct mtx *m;
#ifdef SMP
	uintptr_t tid, v;
#endif

	m = mtxlock2mtx(c);

	KASSERT(m->mtx_lock != MTX_DESTROYED,
	    ("mtx_lock_spin() of destroyed mutex @ %s:%d", file, line));
	KASSERT(LOCK_CLASS(&m->lock_object) == &lock_class_mtx_spin,
	    ("mtx_lock_spin() of sleep mutex %s @ %s:%d",
	    m->lock_object.lo_name, file, line));
	if (mtx_owned(m))
		KASSERT((m->lock_object.lo_flags & LO_RECURSABLE) != 0 ||
		    (opts & MTX_RECURSE) != 0,
	    ("mtx_lock_spin: recursed on non-recursive mutex %s @ %s:%d\n",
		    m->lock_object.lo_name, file, line));
	opts &= ~MTX_RECURSE;
	WITNESS_CHECKORDER(&m->lock_object, opts | LOP_NEWORDER | LOP_EXCLUSIVE,
	    file, line, NULL);
#ifdef SMP
	spinlock_enter();
	tid = (uintptr_t)curthread;
	v = MTX_UNOWNED;
	if (!_mtx_obtain_lock_fetch(m, &v, tid))
		_mtx_lock_spin(m, v, opts, file, line);
	else
		LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(spin__acquire,
		    m, 0, 0, file, line);
#else
	__mtx_lock_spin(m, curthread, opts, file, line);
#endif
	LOCK_LOG_LOCK("LOCK", &m->lock_object, opts, m->mtx_recurse, file,
	    line);
	WITNESS_LOCK(&m->lock_object, opts | LOP_EXCLUSIVE, file, line);
}
示例#4
0
/*
 * _mtx_lock_spin: the tougher part of acquiring an MTX_SPIN lock.
 *
 * This is only called if we need to actually spin for the lock. Recursion
 * is handled inline.
 */
void
_mtx_lock_spin(struct mtx *m, uintptr_t tid, int opts, const char *file,
    int line)
{
	int i = 0;
#ifdef LOCK_PROFILING
	int contested = 0;
	uint64_t waittime = 0;
#endif

	if (LOCK_LOG_TEST(&m->lock_object, opts))
		CTR1(KTR_LOCK, "_mtx_lock_spin: %p spinning", m);

	lock_profile_obtain_lock_failed(&m->lock_object, &contested, &waittime);
	while (!_obtain_lock(m, tid)) {

		/* Give interrupts a chance while we spin. */
		spinlock_exit();
		while (m->mtx_lock != MTX_UNOWNED) {
			if (i++ < 10000000) {
				cpu_spinwait();
				continue;
			}
			if (i < 60000000 || kdb_active || panicstr != NULL)
				DELAY(1);
			else
				_mtx_lock_spin_failed(m);
			cpu_spinwait();
		}
		spinlock_enter();
	}

	if (LOCK_LOG_TEST(&m->lock_object, opts))
		CTR1(KTR_LOCK, "_mtx_lock_spin: %p spin done", m);

	LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_MTX_SPIN_LOCK_ACQUIRE, m,
	    contested, waittime, (file), (line));
	LOCKSTAT_RECORD1(LS_MTX_SPIN_LOCK_SPIN, m, i);
}
示例#5
0
void
cpu_reset(void)
{
	bus_space_handle_t pmc;
	uint32_t reg;

	printf("Resetting...\n");
	bus_space_map(fdtbus_bs_tag, PMC_PHYSBASE, PMC_SIZE, 0, &pmc);

	reg = bus_space_read_4(fdtbus_bs_tag, pmc, PMC_SCRATCH0);
	reg &= PMC_SCRATCH0_MODE_MASK;
	bus_space_write_4(fdtbus_bs_tag, pmc, PMC_SCRATCH0,
	   reg | PMC_SCRATCH0_MODE_BOOTLOADER); 	/* boot to bootloader */
	bus_space_read_4(fdtbus_bs_tag, pmc, PMC_SCRATCH0);

	reg = bus_space_read_4(fdtbus_bs_tag, pmc, PMC_CONTROL_REG);
	spinlock_enter();
	dsb();
	bus_space_write_4(fdtbus_bs_tag, pmc, PMC_CONTROL_REG, reg | 0x10);
	bus_space_read_4(fdtbus_bs_tag, pmc, PMC_CONTROL_REG);
	while(1)
		;

}
示例#6
0
/*
 * This function is called when a thread is about to be put on run queue
 * because it has been made runnable or its priority has been adjusted.  It
 * determines if the new thread should be immediately preempted to.  If so,
 * it switches to it and eventually returns true.  If not, it returns false
 * so that the caller may place the thread on an appropriate run queue.
 */
int
maybe_preempt(struct thread *td)
{
#ifdef PREEMPTION
	struct thread *ctd;
	int cpri, pri;

	/*
	 * The new thread should not preempt the current thread if any of the
	 * following conditions are true:
	 *
	 *  - The kernel is in the throes of crashing (panicstr).
	 *  - The current thread has a higher (numerically lower) or
	 *    equivalent priority.  Note that this prevents curthread from
	 *    trying to preempt to itself.
	 *  - It is too early in the boot for context switches (cold is set).
	 *  - The current thread has an inhibitor set or is in the process of
	 *    exiting.  In this case, the current thread is about to switch
	 *    out anyways, so there's no point in preempting.  If we did,
	 *    the current thread would not be properly resumed as well, so
	 *    just avoid that whole landmine.
	 *  - If the new thread's priority is not a realtime priority and
	 *    the current thread's priority is not an idle priority and
	 *    FULL_PREEMPTION is disabled.
	 *
	 * If all of these conditions are false, but the current thread is in
	 * a nested critical section, then we have to defer the preemption
	 * until we exit the critical section.  Otherwise, switch immediately
	 * to the new thread.
	 */
	ctd = curthread;
	THREAD_LOCK_ASSERT(td, MA_OWNED);
	KASSERT((td->td_inhibitors == 0),
			("maybe_preempt: trying to run inhibited thread"));
	pri = td->td_priority;
	cpri = ctd->td_priority;
	if (panicstr != NULL || pri >= cpri || cold /* || dumping */ ||
	    TD_IS_INHIBITED(ctd))
		return (0);
#ifndef FULL_PREEMPTION
	if (pri > PRI_MAX_ITHD && cpri < PRI_MIN_IDLE)
		return (0);
#endif

	if (ctd->td_critnest > 1) {
		CTR1(KTR_PROC, "maybe_preempt: in critical section %d",
		    ctd->td_critnest);
		ctd->td_owepreempt = 1;
		return (0);
	}
	/*
	 * Thread is runnable but not yet put on system run queue.
	 */
	MPASS(ctd->td_lock == td->td_lock);
	MPASS(TD_ON_RUNQ(td));
	TD_SET_RUNNING(td);
	CTR3(KTR_PROC, "preempting to thread %p (pid %d, %s)\n", td,
	    td->td_proc->p_pid, td->td_name);
	mi_switch(SW_INVOL | SW_PREEMPT | SWT_PREEMPT, td);
	/*
	 * td's lock pointer may have changed.  We have to return with it
	 * locked.
	 */
	spinlock_enter();
	thread_unlock(ctd);
	thread_lock(td);
	spinlock_exit();
	return (1);
#else
	return (0);
#endif
}
示例#7
0
void
_thread_lock_flags(struct thread *td, int opts, const char *file, int line)
{
	struct mtx *m;
	uintptr_t tid;
	int i;
#ifdef LOCK_PROFILING
	int contested = 0;
	uint64_t waittime = 0;
#endif
#ifdef KDTRACE_HOOKS
	uint64_t spin_cnt = 0;
#endif

	i = 0;
	tid = (uintptr_t)curthread;
	for (;;) {
retry:
		spinlock_enter();
		m = td->td_lock;
		KASSERT(m->mtx_lock != MTX_DESTROYED,
		    ("thread_lock() of destroyed mutex @ %s:%d", file, line));
		KASSERT(LOCK_CLASS(&m->lock_object) == &lock_class_mtx_spin,
		    ("thread_lock() of sleep mutex %s @ %s:%d",
		    m->lock_object.lo_name, file, line));
		if (mtx_owned(m))
			KASSERT((m->lock_object.lo_flags & LO_RECURSABLE) != 0,
	    ("thread_lock: recursed on non-recursive mutex %s @ %s:%d\n",
			    m->lock_object.lo_name, file, line));
		WITNESS_CHECKORDER(&m->lock_object,
		    opts | LOP_NEWORDER | LOP_EXCLUSIVE, file, line, NULL);
		while (!_obtain_lock(m, tid)) {
#ifdef KDTRACE_HOOKS
			spin_cnt++;
#endif
			if (m->mtx_lock == tid) {
				m->mtx_recurse++;
				break;
			}
			lock_profile_obtain_lock_failed(&m->lock_object,
			    &contested, &waittime);
			/* Give interrupts a chance while we spin. */
			spinlock_exit();
			while (m->mtx_lock != MTX_UNOWNED) {
				if (i++ < 10000000)
					cpu_spinwait();
				else if (i < 60000000 ||
				    kdb_active || panicstr != NULL)
					DELAY(1);
				else
					_mtx_lock_spin_failed(m);
				cpu_spinwait();
				if (m != td->td_lock)
					goto retry;
			}
			spinlock_enter();
		}
		if (m == td->td_lock)
			break;
		_rel_spin_lock(m);	/* does spinlock_exit() */
#ifdef KDTRACE_HOOKS
		spin_cnt++;
#endif
	}
	if (m->mtx_recurse == 0)
		LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_MTX_SPIN_LOCK_ACQUIRE,
		    m, contested, waittime, (file), (line));
	LOCK_LOG_LOCK("LOCK", &m->lock_object, opts, m->mtx_recurse, file,
	    line);
	WITNESS_LOCK(&m->lock_object, opts | LOP_EXCLUSIVE, file, line);
	LOCKSTAT_RECORD1(LS_THREAD_LOCK_SPIN, m, spin_cnt);
}
示例#8
0
void
smp_rendezvous_cpus(cpuset_t map,
	void (* setup_func)(void *), 
	void (* action_func)(void *),
	void (* teardown_func)(void *),
	void *arg)
{
	int curcpumap, i, ncpus = 0;

	/* Look comments in the !SMP case. */
	if (!smp_started) {
		spinlock_enter();
		if (setup_func != NULL)
			setup_func(arg);
		if (action_func != NULL)
			action_func(arg);
		if (teardown_func != NULL)
			teardown_func(arg);
		spinlock_exit();
		return;
	}

	CPU_FOREACH(i) {
		if (CPU_ISSET(i, &map))
			ncpus++;
	}
	if (ncpus == 0)
		panic("ncpus is 0 with non-zero map");

	mtx_lock_spin(&smp_ipi_mtx);

	/* Pass rendezvous parameters via global variables. */
	smp_rv_ncpus = ncpus;
	smp_rv_setup_func = setup_func;
	smp_rv_action_func = action_func;
	smp_rv_teardown_func = teardown_func;
	smp_rv_func_arg = arg;
	smp_rv_waiters[1] = 0;
	smp_rv_waiters[2] = 0;
	smp_rv_waiters[3] = 0;
	atomic_store_rel_int(&smp_rv_waiters[0], 0);

	/*
	 * Signal other processors, which will enter the IPI with
	 * interrupts off.
	 */
	curcpumap = CPU_ISSET(curcpu, &map);
	CPU_CLR(curcpu, &map);
	ipi_selected(map, IPI_RENDEZVOUS);

	/* Check if the current CPU is in the map */
	if (curcpumap != 0)
		smp_rendezvous_action();

	/*
	 * Ensure that the master CPU waits for all the other
	 * CPUs to finish the rendezvous, so that smp_rv_*
	 * pseudo-structure and the arg are guaranteed to not
	 * be in use.
	 */
	while (atomic_load_acq_int(&smp_rv_waiters[3]) < ncpus)
		cpu_spinwait();

	mtx_unlock_spin(&smp_ipi_mtx);
}
示例#9
0
static int
atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
    enum intr_polarity pol)
{
	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
	u_int vector;

	/* Map conforming values to edge/hi and sanity check the values. */
	if (trig == INTR_TRIGGER_CONFORM)
		trig = INTR_TRIGGER_EDGE;
	if (pol == INTR_POLARITY_CONFORM)
		pol = INTR_POLARITY_HIGH;
	vector = atpic_vector(isrc);
	if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
	    (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
		printf(
		"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
		    vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
		    pol == INTR_POLARITY_HIGH ? "high" : "low");
		return (EINVAL);
	}

	/* If there is no change, just return. */
	if (ai->at_trigger == trig)
		return (0);

#ifdef PC98
	if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
	    trig == INTR_TRIGGER_LEVEL) {
		if (bootverbose)
			printf(
		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
			    vector);
		return (EINVAL);
	}
	return (ENXIO);
#else
	/*
	 * Certain IRQs can never be level/lo, so don't try to set them
	 * that way if asked.  At least some ELCR registers ignore setting
	 * these bits as well.
	 */
	if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
	    trig == INTR_TRIGGER_LEVEL) {
		if (bootverbose)
			printf(
		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
			    vector);
		return (EINVAL);
	}
	if (!elcr_found) {
		if (bootverbose)
			printf("atpic: No ELCR to configure IRQ%u as %s\n",
			    vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
			    "level/low");
		return (ENXIO);
	}
	if (bootverbose)
		printf("atpic: Programming IRQ%u as %s\n", vector,
		    trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
	spinlock_enter();
	elcr_write_trigger(atpic_vector(isrc), trig);
	ai->at_trigger = trig;
	spinlock_exit();
	return (0);
#endif /* PC98 */
}
示例#10
0
void
vpanic(const char *fmt, va_list ap)
{
#ifdef SMP
	cpuset_t other_cpus;
#endif
	struct thread *td = curthread;
	int bootopt, newpanic;
	static char buf[256];

	spinlock_enter();

#ifdef SMP
	/*
	 * stop_cpus_hard(other_cpus) should prevent multiple CPUs from
	 * concurrently entering panic.  Only the winner will proceed
	 * further.
	 */
	if (panicstr == NULL && !kdb_active) {
		other_cpus = all_cpus;
		CPU_CLR(PCPU_GET(cpuid), &other_cpus);
		stop_cpus_hard(other_cpus);
	}

	/*
	 * Ensure that the scheduler is stopped while panicking, even if panic
	 * has been entered from kdb.
	 */
	td->td_stopsched = 1;
#endif

	bootopt = RB_AUTOBOOT;
	newpanic = 0;
	if (panicstr)
		bootopt |= RB_NOSYNC;
	else {
		bootopt |= RB_DUMP;
		panicstr = fmt;
		newpanic = 1;
	}

	if (newpanic) {
		(void)vsnprintf(buf, sizeof(buf), fmt, ap);
		panicstr = buf;
		cngrab();
		printf("panic: %s\n", buf);
	} else {
		printf("panic: ");
		vprintf(fmt, ap);
		printf("\n");
	}
#ifdef SMP
	printf("cpuid = %d\n", PCPU_GET(cpuid));
#endif

#ifdef KDB
	if (newpanic && trace_on_panic)
		kdb_backtrace();
	if (debugger_on_panic)
		kdb_enter(KDB_WHY_PANIC, "panic");
#endif
	/*thread_lock(td); */
	td->td_flags |= TDF_INPANIC;
	/* thread_unlock(td); */
	if (!sync_on_panic)
		bootopt |= RB_NOSYNC;
	kern_reboot(bootopt);
}
示例#11
0
void
thread_lock_flags_(struct thread *td, int opts, const char *file, int line)
{
	struct mtx *m;
	uintptr_t tid;
	struct lock_delay_arg lda;
#ifdef LOCK_PROFILING
	int contested = 0;
	uint64_t waittime = 0;
#endif
#ifdef KDTRACE_HOOKS
	int64_t spin_time = 0;
#endif

	tid = (uintptr_t)curthread;

	if (SCHEDULER_STOPPED()) {
		/*
		 * Ensure that spinlock sections are balanced even when the
		 * scheduler is stopped, since we may otherwise inadvertently
		 * re-enable interrupts while dumping core.
		 */
		spinlock_enter();
		return;
	}

	lock_delay_arg_init(&lda, &mtx_spin_delay);

#ifdef KDTRACE_HOOKS
	spin_time -= lockstat_nsecs(&td->td_lock->lock_object);
#endif
	for (;;) {
retry:
		spinlock_enter();
		m = td->td_lock;
		KASSERT(m->mtx_lock != MTX_DESTROYED,
		    ("thread_lock() of destroyed mutex @ %s:%d", file, line));
		KASSERT(LOCK_CLASS(&m->lock_object) == &lock_class_mtx_spin,
		    ("thread_lock() of sleep mutex %s @ %s:%d",
		    m->lock_object.lo_name, file, line));
		if (mtx_owned(m))
			KASSERT((m->lock_object.lo_flags & LO_RECURSABLE) != 0,
	    ("thread_lock: recursed on non-recursive mutex %s @ %s:%d\n",
			    m->lock_object.lo_name, file, line));
		WITNESS_CHECKORDER(&m->lock_object,
		    opts | LOP_NEWORDER | LOP_EXCLUSIVE, file, line, NULL);
		for (;;) {
			if (m->mtx_lock == MTX_UNOWNED && _mtx_obtain_lock(m, tid))
				break;
			if (m->mtx_lock == tid) {
				m->mtx_recurse++;
				break;
			}
#ifdef HWPMC_HOOKS
			PMC_SOFT_CALL( , , lock, failed);
#endif
			lock_profile_obtain_lock_failed(&m->lock_object,
			    &contested, &waittime);
			/* Give interrupts a chance while we spin. */
			spinlock_exit();
			while (m->mtx_lock != MTX_UNOWNED) {
				if (lda.spin_cnt < 10000000) {
					lock_delay(&lda);
				} else {
					lda.spin_cnt++;
					if (lda.spin_cnt < 60000000 ||
					    kdb_active || panicstr != NULL)
						DELAY(1);
					else
						_mtx_lock_spin_failed(m);
					cpu_spinwait();
				}
				if (m != td->td_lock)
					goto retry;
			}
			spinlock_enter();
		}
		if (m == td->td_lock)
			break;
		__mtx_unlock_spin(m);	/* does spinlock_exit() */
	}
#ifdef KDTRACE_HOOKS
	spin_time += lockstat_nsecs(&m->lock_object);
#endif
	if (m->mtx_recurse == 0)
		LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(spin__acquire, m,
		    contested, waittime, file, line);
	LOCK_LOG_LOCK("LOCK", &m->lock_object, opts, m->mtx_recurse, file,
	    line);
	WITNESS_LOCK(&m->lock_object, opts | LOP_EXCLUSIVE, file, line);
#ifdef KDTRACE_HOOKS
	if (spin_time != 0)
		LOCKSTAT_RECORD1(thread__spin, m, spin_time);
#endif
}
示例#12
0
/*
 * _mtx_lock_spin_cookie: the tougher part of acquiring an MTX_SPIN lock.
 *
 * This is only called if we need to actually spin for the lock. Recursion
 * is handled inline.
 */
void
_mtx_lock_spin_cookie(volatile uintptr_t *c, uintptr_t tid, int opts,
    const char *file, int line)
{
	struct mtx *m;
	struct lock_delay_arg lda;
#ifdef LOCK_PROFILING
	int contested = 0;
	uint64_t waittime = 0;
#endif
#ifdef KDTRACE_HOOKS
	int64_t spin_time = 0;
#endif

	if (SCHEDULER_STOPPED())
		return;

	lock_delay_arg_init(&lda, &mtx_spin_delay);
	m = mtxlock2mtx(c);

	if (LOCK_LOG_TEST(&m->lock_object, opts))
		CTR1(KTR_LOCK, "_mtx_lock_spin: %p spinning", m);
	KTR_STATE1(KTR_SCHED, "thread", sched_tdname((struct thread *)tid),
	    "spinning", "lockname:\"%s\"", m->lock_object.lo_name);

#ifdef HWPMC_HOOKS
	PMC_SOFT_CALL( , , lock, failed);
#endif
	lock_profile_obtain_lock_failed(&m->lock_object, &contested, &waittime);
#ifdef KDTRACE_HOOKS
	spin_time -= lockstat_nsecs(&m->lock_object);
#endif
	for (;;) {
		if (m->mtx_lock == MTX_UNOWNED && _mtx_obtain_lock(m, tid))
			break;
		/* Give interrupts a chance while we spin. */
		spinlock_exit();
		while (m->mtx_lock != MTX_UNOWNED) {
			if (lda.spin_cnt < 10000000) {
				lock_delay(&lda);
				continue;
			}
			lda.spin_cnt++;
			if (lda.spin_cnt < 60000000 || kdb_active ||
			    panicstr != NULL)
				DELAY(1);
			else
				_mtx_lock_spin_failed(m);
			cpu_spinwait();
		}
		spinlock_enter();
	}
#ifdef KDTRACE_HOOKS
	spin_time += lockstat_nsecs(&m->lock_object);
#endif

	if (LOCK_LOG_TEST(&m->lock_object, opts))
		CTR1(KTR_LOCK, "_mtx_lock_spin: %p spin done", m);
	KTR_STATE0(KTR_SCHED, "thread", sched_tdname((struct thread *)tid),
	    "running");

#ifdef KDTRACE_HOOKS
	LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(spin__acquire, m,
	    contested, waittime, file, line);
	if (spin_time != 0)
		LOCKSTAT_RECORD1(spin__spin, m, spin_time);
#endif
}
示例#13
0
void
thread_lock_flags_(struct thread *td, int opts, const char *file, int line)
{
	struct mtx *m;
	uintptr_t tid, v;
	struct lock_delay_arg lda;
#ifdef LOCK_PROFILING
	int contested = 0;
	uint64_t waittime = 0;
#endif
#ifdef KDTRACE_HOOKS
	int64_t spin_time = 0;
#endif
#if defined(KDTRACE_HOOKS) || defined(LOCK_PROFILING)
	int doing_lockprof = 1;
#endif

	tid = (uintptr_t)curthread;

	if (SCHEDULER_STOPPED()) {
		/*
		 * Ensure that spinlock sections are balanced even when the
		 * scheduler is stopped, since we may otherwise inadvertently
		 * re-enable interrupts while dumping core.
		 */
		spinlock_enter();
		return;
	}

	lock_delay_arg_init(&lda, &mtx_spin_delay);

#ifdef LOCK_PROFILING
	doing_lockprof = 1;
#elif defined(KDTRACE_HOOKS)
	doing_lockprof = lockstat_enabled;
	if (__predict_false(doing_lockprof))
		spin_time -= lockstat_nsecs(&td->td_lock->lock_object);
#endif
	for (;;) {
retry:
		v = MTX_UNOWNED;
		spinlock_enter();
		m = td->td_lock;
		thread_lock_validate(m, opts, file, line);
		for (;;) {
			if (_mtx_obtain_lock_fetch(m, &v, tid))
				break;
			if (v == MTX_UNOWNED)
				continue;
			if (v == tid) {
				m->mtx_recurse++;
				break;
			}
#ifdef HWPMC_HOOKS
			PMC_SOFT_CALL( , , lock, failed);
#endif
			lock_profile_obtain_lock_failed(&m->lock_object,
			    &contested, &waittime);
			/* Give interrupts a chance while we spin. */
			spinlock_exit();
			do {
				if (lda.spin_cnt < 10000000) {
					lock_delay(&lda);
				} else {
					lda.spin_cnt++;
					if (lda.spin_cnt < 60000000 ||
					    kdb_active || panicstr != NULL)
						DELAY(1);
					else
						_mtx_lock_spin_failed(m);
					cpu_spinwait();
				}
				if (m != td->td_lock)
					goto retry;
				v = MTX_READ_VALUE(m);
			} while (v != MTX_UNOWNED);
			spinlock_enter();
		}
		if (m == td->td_lock)
			break;
		__mtx_unlock_spin(m);	/* does spinlock_exit() */
	}
	LOCK_LOG_LOCK("LOCK", &m->lock_object, opts, m->mtx_recurse, file,
	    line);
	WITNESS_LOCK(&m->lock_object, opts | LOP_EXCLUSIVE, file, line);

#if defined(KDTRACE_HOOKS) || defined(LOCK_PROFILING)
	if (__predict_true(!doing_lockprof))
		return;
#endif
#ifdef KDTRACE_HOOKS
	spin_time += lockstat_nsecs(&m->lock_object);
#endif
	if (m->mtx_recurse == 0)
		LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(spin__acquire, m,
		    contested, waittime, file, line);
#ifdef KDTRACE_HOOKS
	if (lda.spin_cnt != 0)
		LOCKSTAT_RECORD1(thread__spin, m, spin_time);
#endif
}
示例#14
0
void
_mtx_lock_spin_cookie(volatile uintptr_t *c, uintptr_t v)
#endif
{
	struct mtx *m;
	struct lock_delay_arg lda;
	uintptr_t tid;
#ifdef LOCK_PROFILING
	int contested = 0;
	uint64_t waittime = 0;
#endif
#ifdef KDTRACE_HOOKS
	int64_t spin_time = 0;
#endif
#if defined(KDTRACE_HOOKS) || defined(LOCK_PROFILING)
	int doing_lockprof;
#endif

	tid = (uintptr_t)curthread;
	m = mtxlock2mtx(c);

	if (__predict_false(v == MTX_UNOWNED))
		v = MTX_READ_VALUE(m);

	if (__predict_false(v == tid)) {
		m->mtx_recurse++;
		return;
	}

	if (SCHEDULER_STOPPED())
		return;

	lock_delay_arg_init(&lda, &mtx_spin_delay);

	if (LOCK_LOG_TEST(&m->lock_object, opts))
		CTR1(KTR_LOCK, "_mtx_lock_spin: %p spinning", m);
	KTR_STATE1(KTR_SCHED, "thread", sched_tdname((struct thread *)tid),
	    "spinning", "lockname:\"%s\"", m->lock_object.lo_name);

#ifdef HWPMC_HOOKS
	PMC_SOFT_CALL( , , lock, failed);
#endif
	lock_profile_obtain_lock_failed(&m->lock_object, &contested, &waittime);
#ifdef LOCK_PROFILING
	doing_lockprof = 1;
#elif defined(KDTRACE_HOOKS)
	doing_lockprof = lockstat_enabled;
	if (__predict_false(doing_lockprof))
		spin_time -= lockstat_nsecs(&m->lock_object);
#endif
	for (;;) {
		if (v == MTX_UNOWNED) {
			if (_mtx_obtain_lock_fetch(m, &v, tid))
				break;
			continue;
		}
		/* Give interrupts a chance while we spin. */
		spinlock_exit();
		do {
			if (lda.spin_cnt < 10000000) {
				lock_delay(&lda);
			} else {
				lda.spin_cnt++;
				if (lda.spin_cnt < 60000000 || kdb_active ||
				    panicstr != NULL)
					DELAY(1);
				else
					_mtx_lock_spin_failed(m);
				cpu_spinwait();
			}
			v = MTX_READ_VALUE(m);
		} while (v != MTX_UNOWNED);
		spinlock_enter();
	}

	if (LOCK_LOG_TEST(&m->lock_object, opts))
		CTR1(KTR_LOCK, "_mtx_lock_spin: %p spin done", m);
	KTR_STATE0(KTR_SCHED, "thread", sched_tdname((struct thread *)tid),
	    "running");

#if defined(KDTRACE_HOOKS) || defined(LOCK_PROFILING)
	if (__predict_true(!doing_lockprof))
		return;
#endif
#ifdef KDTRACE_HOOKS
	spin_time += lockstat_nsecs(&m->lock_object);
#endif
	LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(spin__acquire, m,
	    contested, waittime, file, line);
#ifdef KDTRACE_HOOKS
	if (lda.spin_cnt != 0)
		LOCKSTAT_RECORD1(spin__spin, m, spin_time);
#endif
}
示例#15
0
void
thread_lock_flags_(struct thread *td, int opts, const char *file, int line)
{
	struct mtx *m;
	uintptr_t tid;
	int i;
#ifdef LOCK_PROFILING
	int contested = 0;
	uint64_t waittime = 0;
#endif
#ifdef KDTRACE_HOOKS
	int64_t spin_time = 0;
#endif

	i = 0;
	tid = (uintptr_t)curthread;

	if (SCHEDULER_STOPPED())
		return;

#ifdef KDTRACE_HOOKS
	spin_time -= lockstat_nsecs(&td->td_lock->lock_object);
#endif
	for (;;) {
retry:
		spinlock_enter();
		m = td->td_lock;
		KASSERT(m->mtx_lock != MTX_DESTROYED,
		    ("thread_lock() of destroyed mutex @ %s:%d", file, line));
		KASSERT(LOCK_CLASS(&m->lock_object) == &lock_class_mtx_spin,
		    ("thread_lock() of sleep mutex %s @ %s:%d",
		    m->lock_object.lo_name, file, line));
		if (mtx_owned(m))
			KASSERT((m->lock_object.lo_flags & LO_RECURSABLE) != 0,
	    ("thread_lock: recursed on non-recursive mutex %s @ %s:%d\n",
			    m->lock_object.lo_name, file, line));
		WITNESS_CHECKORDER(&m->lock_object,
		    opts | LOP_NEWORDER | LOP_EXCLUSIVE, file, line, NULL);
		while (!_mtx_obtain_lock(m, tid)) {
			if (m->mtx_lock == tid) {
				m->mtx_recurse++;
				break;
			}
#ifdef HWPMC_HOOKS
			PMC_SOFT_CALL( , , lock, failed);
#endif
			lock_profile_obtain_lock_failed(&m->lock_object,
			    &contested, &waittime);
			/* Give interrupts a chance while we spin. */
			spinlock_exit();
			while (m->mtx_lock != MTX_UNOWNED) {
				if (i++ < 10000000)
					cpu_spinwait();
				else if (i < 60000000 ||
				    kdb_active || panicstr != NULL)
					DELAY(1);
				else
					_mtx_lock_spin_failed(m);
				cpu_spinwait();
				if (m != td->td_lock)
					goto retry;
			}
			spinlock_enter();
		}
		if (m == td->td_lock)
			break;
		__mtx_unlock_spin(m);	/* does spinlock_exit() */
	}
#ifdef KDTRACE_HOOKS
	spin_time += lockstat_nsecs(&m->lock_object);
#endif
	if (m->mtx_recurse == 0)
		LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(spin__acquire, m,
		    contested, waittime, file, line);
	LOCK_LOG_LOCK("LOCK", &m->lock_object, opts, m->mtx_recurse, file,
	    line);
	WITNESS_LOCK(&m->lock_object, opts | LOP_EXCLUSIVE, file, line);
	LOCKSTAT_RECORD1(thread__spin, m, spin_time);
}
示例#16
0
/*
 * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
 * and then reboots.  If we are called twice, then we avoid trying to sync
 * the disks as this often leads to recursive panics.
 */
void
panic(const char *fmt, ...)
{
#ifdef SMP
	static volatile u_int panic_cpu = NOCPU;
	cpuset_t other_cpus;
#endif
	struct thread *td = curthread;
	int bootopt, newpanic;
	va_list ap;
	static char buf[256];

	if (stop_scheduler_on_panic)
		spinlock_enter();
	else
		critical_enter();

#ifdef SMP
	/*
	 * We don't want multiple CPU's to panic at the same time, so we
	 * use panic_cpu as a simple spinlock.  We have to keep checking
	 * panic_cpu if we are spinning in case the panic on the first
	 * CPU is canceled.
	 */
	if (panic_cpu != PCPU_GET(cpuid))
		while (atomic_cmpset_int(&panic_cpu, NOCPU,
		    PCPU_GET(cpuid)) == 0)
			while (panic_cpu != NOCPU)
				; /* nothing */

	if (stop_scheduler_on_panic) {
		if (panicstr == NULL && !kdb_active) {
			other_cpus = all_cpus;
			CPU_CLR(PCPU_GET(cpuid), &other_cpus);
			stop_cpus_hard(other_cpus);
		}

		/*
		 * We set stop_scheduler here and not in the block above,
		 * because we want to ensure that if panic has been called and
		 * stop_scheduler_on_panic is true, then stop_scheduler will
		 * always be set.  Even if panic has been entered from kdb.
		 */
		td->td_stopsched = 1;
	}
#endif

	bootopt = RB_AUTOBOOT;
	newpanic = 0;
	if (panicstr)
		bootopt |= RB_NOSYNC;
	else {
		bootopt |= RB_DUMP;
		panicstr = fmt;
		newpanic = 1;
	}

	va_start(ap, fmt);
	if (newpanic) {
		(void)vsnprintf(buf, sizeof(buf), fmt, ap);
		panicstr = buf;
		cngrab();
		printf("panic: %s\n", buf);
	} else {
		printf("panic: ");
		vprintf(fmt, ap);
		printf("\n");
	}
	va_end(ap);
#ifdef SMP
	printf("cpuid = %d\n", PCPU_GET(cpuid));
#endif

#ifdef KDB
	if (newpanic && trace_on_panic)
		kdb_backtrace();
	if (debugger_on_panic)
		kdb_enter(KDB_WHY_PANIC, "panic");
#endif
	/*thread_lock(td); */
	td->td_flags |= TDF_INPANIC;
	/* thread_unlock(td); */
	if (!sync_on_panic)
		bootopt |= RB_NOSYNC;
	if (!stop_scheduler_on_panic)
		critical_exit();
	kern_reboot(bootopt);
}