⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dtrace.c

📁 Sun Solaris 10 中的 DTrace 组件的源代码。请参看: http://www.sun.com/software/solaris/observability.jsp
💻 C
📖 第 1 页 / 共 5 页
字号:
		dtrace_speculation_commit(state, cpu, i + 1);	}	dtrace_interrupt_enable(cookie);}/* * Note:  not called from probe context.  This function is called * asynchronously (and at a regular interval) to clean any speculations that * are in the COMMITTINGMANY or DISCARDING states.  If it discovers that there * is work to be done, it cross calls all CPUs to perform that work; * COMMITMANY and DISCARDING speculations may not be transitioned back to the * INACTIVE state until they have been cleaned by all CPUs. */static voiddtrace_speculation_clean(dtrace_state_t *state){	int work = 0, rv;	dtrace_specid_t i;	for (i = 0; i < state->dts_nspeculations; i++) {		dtrace_speculation_t *spec = &state->dts_speculations[i];		ASSERT(!spec->dtsp_cleaning);		if (spec->dtsp_state != DTRACESPEC_DISCARDING &&		    spec->dtsp_state != DTRACESPEC_COMMITTINGMANY)			continue;		work++;		spec->dtsp_cleaning = 1;	}	if (!work)		return;	dtrace_xcall(DTRACE_CPUALL,	    (dtrace_xcall_t)dtrace_speculation_clean_here, state);	/*	 * We now know that all CPUs have committed or discarded their	 * speculation buffers, as appropriate.  We can now set the state	 * to inactive.	 */	for (i = 0; i < state->dts_nspeculations; i++) {		dtrace_speculation_t *spec = &state->dts_speculations[i];		dtrace_speculation_state_t current, new;		if (!spec->dtsp_cleaning)			continue;		current = spec->dtsp_state;		ASSERT(current == DTRACESPEC_DISCARDING ||		    current == DTRACESPEC_COMMITTINGMANY);		new = DTRACESPEC_INACTIVE;		rv = dtrace_cas32((uint32_t *)&spec->dtsp_state, current, new);		ASSERT(rv == current);		spec->dtsp_cleaning = 0;	}}/* * Called as part of a speculate() to get the speculative buffer associated * with a given speculation.  Returns NULL if the specified speculation is not * in an ACTIVE state.  If the speculation is in the ACTIVEONE state -- and * the active CPU is not the specified CPU -- the speculation will be * atomically transitioned into the ACTIVEMANY state. */static dtrace_buffer_t *dtrace_speculation_buffer(dtrace_state_t *state, processorid_t cpuid,    dtrace_specid_t which){	dtrace_speculation_t *spec;	dtrace_speculation_state_t current, new;	dtrace_buffer_t *buf;	if (which == 0)		return (NULL);	if (which > state->dts_nspeculations) {		cpu_core[cpuid].cpuc_dtrace_flags |= CPU_DTRACE_ILLOP;		return (NULL);	}	spec = &state->dts_speculations[which - 1];	buf = &spec->dtsp_buffer[cpuid];	do {		current = spec->dtsp_state;		switch (current) {		case DTRACESPEC_INACTIVE:		case DTRACESPEC_COMMITTINGMANY:		case DTRACESPEC_DISCARDING:			return (NULL);		case DTRACESPEC_COMMITTING:			ASSERT(buf->dtb_offset == 0);			return (NULL);		case DTRACESPEC_ACTIVEONE:			/*			 * This speculation is currently active on one CPU.			 * Check the offset in the buffer; if it's non-zero,			 * that CPU must be us (and we leave the state alone).			 * If it's zero, assume that we're starting on a new			 * CPU -- and change the state to indicate that the			 * speculation is active on more than one CPU.			 */			if (buf->dtb_offset != 0)				return (buf);			new = DTRACESPEC_ACTIVEMANY;			break;		case DTRACESPEC_ACTIVEMANY:			return (buf);		case DTRACESPEC_ACTIVE:			new = DTRACESPEC_ACTIVEONE;			break;		default:			ASSERT(0);		}	} while (dtrace_cas32((uint32_t *)&spec->dtsp_state,	    current, new) != current);	ASSERT(new == DTRACESPEC_ACTIVEONE || new == DTRACESPEC_ACTIVEMANY);	return (buf);}/* * This function implements the DIF emulator's variable lookups.  The emulator * passes a reserved variable identifier and optional built-in array index. */static uint64_tdtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,    uint64_t i){	/*	 * If we're accessing one of the uncached arguments, we'll turn this	 * into a reference in the args array.	 */	if (v >= DIF_VAR_ARG0 && v <= DIF_VAR_ARG9) {		i = v - DIF_VAR_ARG0;		v = DIF_VAR_ARGS;	}	switch (v) {	case DIF_VAR_ARGS:		ASSERT(mstate->dtms_present & DTRACE_MSTATE_ARGS);		if (i >= sizeof (mstate->dtms_arg) /		    sizeof (mstate->dtms_arg[0])) {			int aframes = mstate->dtms_probe->dtpr_aframes + 2;			dtrace_provider_t *pv;			uint64_t val;			pv = mstate->dtms_probe->dtpr_provider;			if (pv->dtpv_pops.dtps_getargval != NULL)				val = pv->dtpv_pops.dtps_getargval(pv->dtpv_arg,				    mstate->dtms_probe->dtpr_id,				    mstate->dtms_probe->dtpr_arg, i, aframes);			else				val = dtrace_getarg(i, aframes);			/*			 * This is regrettably required to keep the compiler			 * from tail-optimizing the call to dtrace_getarg().			 * The condition always evaluates to true, but the			 * compiler has no way of figuring that out a priori.			 * (None of this would be necessary if the compiler			 * could be relied upon to _always_ tail-optimize			 * the call to dtrace_getarg() -- but it can't.)			 */			if (mstate->dtms_probe != NULL)				return (val);			ASSERT(0);		}		return (mstate->dtms_arg[i]);	case DIF_VAR_UREGS: {		klwp_t *lwp;		if (!dtrace_priv_proc(state))			return (0);		if ((lwp = curthread->t_lwp) == NULL) {			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = NULL;			return (0);		}		return (dtrace_getreg(lwp->lwp_regs, i));	}	case DIF_VAR_CURTHREAD:		if (!dtrace_priv_kernel(state))			return (0);		return ((uint64_t)(uintptr_t)curthread);	case DIF_VAR_TIMESTAMP:		if (!(mstate->dtms_present & DTRACE_MSTATE_TIMESTAMP)) {			mstate->dtms_timestamp = dtrace_gethrtime();			mstate->dtms_present |= DTRACE_MSTATE_TIMESTAMP;		}		return (mstate->dtms_timestamp);	case DIF_VAR_VTIMESTAMP:		ASSERT(dtrace_vtime_references != 0);		return (curthread->t_dtrace_vtime);	case DIF_VAR_WALLTIMESTAMP:		if (!(mstate->dtms_present & DTRACE_MSTATE_WALLTIMESTAMP)) {			mstate->dtms_walltimestamp = dtrace_gethrestime();			mstate->dtms_present |= DTRACE_MSTATE_WALLTIMESTAMP;		}		return (mstate->dtms_walltimestamp);	case DIF_VAR_IPL:		if (!dtrace_priv_kernel(state))			return (0);		if (!(mstate->dtms_present & DTRACE_MSTATE_IPL)) {			mstate->dtms_ipl = dtrace_getipl();			mstate->dtms_present |= DTRACE_MSTATE_IPL;		}		return (mstate->dtms_ipl);	case DIF_VAR_EPID:		ASSERT(mstate->dtms_present & DTRACE_MSTATE_EPID);		return (mstate->dtms_epid);	case DIF_VAR_ID:		ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE);		return (mstate->dtms_probe->dtpr_id);	case DIF_VAR_STACKDEPTH:		if (!dtrace_priv_kernel(state))			return (0);		if (!(mstate->dtms_present & DTRACE_MSTATE_STACKDEPTH)) {			int aframes = mstate->dtms_probe->dtpr_aframes + 2;			mstate->dtms_stackdepth = dtrace_getstackdepth(aframes);			mstate->dtms_present |= DTRACE_MSTATE_STACKDEPTH;		}		return (mstate->dtms_stackdepth);	case DIF_VAR_CALLER:		if (!dtrace_priv_kernel(state))			return (0);		if (!(mstate->dtms_present & DTRACE_MSTATE_CALLER)) {			int aframes = mstate->dtms_probe->dtpr_aframes + 2;			if ((mstate->dtms_caller =			    dtrace_caller(aframes)) == -1) {				/*				 * We have failed to do this the quick way;				 * we must resort to the slow and painful				 * approach of calling dtrace_getpcstack().				 */				pc_t caller;				dtrace_getpcstack(&caller, 1, aframes, NULL);				mstate->dtms_caller = caller;			}			mstate->dtms_present |= DTRACE_MSTATE_CALLER;		}		return (mstate->dtms_caller);	case DIF_VAR_PROBEPROV:		ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE);		return ((uint64_t)(uintptr_t)		    mstate->dtms_probe->dtpr_provider->dtpv_name);	case DIF_VAR_PROBEMOD:		ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE);		return ((uint64_t)(uintptr_t)		    mstate->dtms_probe->dtpr_mod);	case DIF_VAR_PROBEFUNC:		ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE);		return ((uint64_t)(uintptr_t)		    mstate->dtms_probe->dtpr_func);	case DIF_VAR_PROBENAME:		ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE);		return ((uint64_t)(uintptr_t)		    mstate->dtms_probe->dtpr_name);	case DIF_VAR_PID:		if (!dtrace_priv_proc(state))			return (0);		/*		 * Note that we are assuming that an unanchored probe is		 * always due to a high-level interrupt.  (And we're assuming		 * that there is only a single high level interrupt.)		 */		if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU))			return (pid0.pid_id);		/*		 * It is always safe to dereference one's own t_procp pointer:		 * it always points to a valid, allocated proc structure.		 * Further, it is always safe to dereference the p_pidp member		 * of one's own proc structure.  (These are truisms becuase		 * threads and processes don't clean up their own state --		 * they leave that task to whomever reaps them.)		 */		return ((uint64_t)curthread->t_procp->p_pidp->pid_id);	case DIF_VAR_TID:		/*		 * See comment in DIF_VAR_PID.		 */		if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU))			return (0);		return ((uint64_t)curthread->t_tid);	case DIF_VAR_EXECNAME:		if (!dtrace_priv_proc(state))			return (0);		/*		 * See comment in DIF_VAR_PID.		 */		if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU))			return ((uint64_t)(uintptr_t)p0.p_user.u_comm);		/*		 * It is always safe to dereference one's own t_procp pointer:		 * it always points to a valid, allocated proc structure.		 * (This is true because threads don't clean up their own		 * state -- they leave that task to whomever reaps them.)		 */		return ((uint64_t)(uintptr_t)		    curthread->t_procp->p_user.u_comm);	case DIF_VAR_ZONENAME:		if (!dtrace_priv_proc(state))			return (0);		/*		 * See comment in DIF_VAR_PID.		 */		if (DTRACE_ANCHORED(mstate->dtms_probe) && CPU_ON_INTR(CPU))			return ((uint64_t)(uintptr_t)p0.p_zone->zone_name);		/*		 * It is always safe to dereference one's own t_procp pointer:		 * it always points to a valid, allocated proc structure.		 * (This is true because threads don't clean up their own		 * state -- they leave that task to whomever reaps them.)		 */		return ((uint64_t)(uintptr_t)		    curthread->t_procp->p_zone->zone_name);	default:		DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);		return (0);	}}/* * Emulate the execution of DTrace ID subroutines invoked by the call opcode. * Notice that we don't bother validating the proper number of arguments or * their types in the tuple stack.  This isn't needed because all argument * interpretation is safe because of our load safety -- the worst that can * happen is that a bogus program can obtain bogus results. */static voiddtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,    dtrace_key_t *tupregs, dtrace_mstate_t *mstate, dtrace_state_t *state){	volatile uint16_t *flags = &cpu_core[CPU->cpu_id].cpuc_dtrace_flags;	volatile uintptr_t *illval = &cpu_core[CPU->cpu_id].cpuc_dtrace_illval;	union {		mutex_impl_t mi;		uint64_t mx;	} m;	union {		krwlock_t ri;		uintptr_t rw;	} r;	switch (subr) {	case DIF_SUBR_RAND:		regs[rd] = (dtrace_gethrtime() * 2416 + 374441) % 1771875;		break;	case DIF_SUBR_MUTEX_OWNED:		m.mx = dtrace_load64(tupregs[0].dttk_value);		if (MUTEX_TYPE_ADAPTIVE(&m.mi))			regs[rd] = MUTEX_OWNER(&m.mi) != MUTEX_NO_OWNER;		else			regs[rd] = LOCK_HELD(&m.mi.m_spin.m_spinlock);		break;	case DIF_SUBR_MUTEX_OWNER:		m.mx = dtrace_load64(tupregs[0].dttk_value);		if (MUTEX_TYPE_ADAPTIVE(&m.mi) &&		    MUTEX_OWNER(&m.mi) != MUTEX_NO_OWNER)			regs[rd] = (uintptr_t)MUTEX_OWNER(&m.mi);		else			regs[rd] = 0;		break;	case DIF_SUBR_MUTEX_TYPE_ADAPTIVE:		m.mx = dtrace_load64(tupregs[0].dttk_value);		regs[rd] = MUTEX_TYPE_ADAPTIVE(&m.mi);		break;	case DIF_SUBR_MUTEX_TYPE_SPIN:		m.mx = dtrace_load64(tupregs[0].dttk_value);		regs[rd] = MUTEX_TYPE_SPIN(&m.mi);		break;	case DIF_SUBR_RW_READ_HELD: {		uintptr_t tmp;		r.rw = dtrace_loadptr(tupregs[0].dttk_value);		regs[rd] = _RW_READ_HELD(&r.ri, tmp);		break;	}	case DIF_SUBR_RW_WRITE_HELD:		r.rw = dtrace_loadptr(tupregs[0].dttk_value);		regs[rd] = _RW_WRITE_HELD(&r.ri);		break;	case DIF_SUBR_RW_ISWRITER:		r.rw = dtrace_loadptr(tupregs[0].dttk_value);		regs[rd] = _RW_ISWRITER(&r.ri);		break;	case DIF_SUBR_BCOPY: {		/*		 * We need to be sure that the destination is in the scratch		 * region -- no other region is allowed.		 */		uintptr_t src = tupregs[0].dttk_value;		uintptr_t dest = tupregs[1].dttk_value;		size_t size = tupregs[2].dttk_value;		if (!dtrace_inscratch(dest, size, mstate)) {			*flags |= CPU_DTRACE_BADADDR;			*illval = regs[rd];			break;		}		dtrace_bcopy((void *)src, (void *)dest, size);		break;	}	case DIF_SUBR_ALLOCA:	case DIF_SUBR_COPYIN: {		uintptr_t dest = P2ROUNDUP(mstate->dtms

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -