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

📄 fasttrap.c

📁 Sun Solaris 10 中的 DTrace 组件的源代码。请参看: http://www.sun.com/software/solaris/observability.jsp
💻 C
📖 第 1 页 / 共 5 页
字号:
	 * Tracepoints whose provider is now defunct are also considered	 * defunct.	 */again:	mutex_enter(&bucket->ftb_mtx);	for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {		if (tp->ftt_pid != pid || tp->ftt_pc != pc ||		    tp->ftt_prov->ftp_defunct)			continue;		/*		 * Now that we've found a matching tracepoint, it would be		 * a decent idea to confirm that the tracepoint is still		 * enabled and the trap instruction hasn't been overwritten.		 * Since this is a little hairy, we'll punt for now.		 */		/*		 * This can't be the first interested probe. We don't have		 * to worry about another thread being in the midst of		 * deleting this tracepoint (which would be the only valid		 * reason for a tracepoint to have no interested probes)		 * since we're holding P_PR_LOCK for this process.		 */		ASSERT(tp->ftt_ids != NULL || tp->ftt_retids != NULL);		if (probe->ftp_type == DTFTP_RETURN ||		    probe->ftp_type == DTFTP_POST_OFFSETS) {			id->fti_next = tp->ftt_retids;			membar_producer();			tp->ftt_retids = id;			membar_producer();		} else {			id->fti_next = tp->ftt_ids;			membar_producer();			tp->ftt_ids = id;			membar_producer();		}		mutex_exit(&bucket->ftb_mtx);		if (new_tp != NULL) {			new_tp->ftt_ids = NULL;			new_tp->ftt_retids = NULL;		}		return (0);	}	/*	 * If we have a good tracepoint ready to go, install it now while	 * we have the lock held and no one can screw with us.	 */	if (new_tp != NULL) {		int rc;		new_tp->ftt_next = bucket->ftb_data;		membar_producer();		bucket->ftb_data = new_tp;		membar_producer();		mutex_exit(&bucket->ftb_mtx);		/*		 * Activate the tracepoint in the isa-specific manner.		 */		if (fasttrap_tracepoint_install(p, new_tp) != 0) {			rc = 1;		} else {			/*			 * Increment the count of the number of tracepoints			 * active in the victim process.			 */			ASSERT(p->p_proc_flag & P_PR_LOCK);			p->p_dtrace_count++;			rc = 0;		}		return (rc);	}	mutex_exit(&bucket->ftb_mtx);	/*	 * Initialize the tracepoint that's been preallocated with the probe.	 */	new_tp = probe->ftp_tps[index].fit_tp;	ASSERT(new_tp->ftt_pid == pid);	ASSERT(new_tp->ftt_pc == pc);	ASSERT(new_tp->ftt_prov == probe->ftp_prov);	ASSERT(new_tp->ftt_ids == NULL);	ASSERT(new_tp->ftt_retids == NULL);	if (probe->ftp_type == DTFTP_RETURN ||	    probe->ftp_type == DTFTP_POST_OFFSETS) {		id->fti_next = NULL;		new_tp->ftt_retids = id;	} else {		id->fti_next = NULL;		new_tp->ftt_ids = id;	}	/*	 * If the isa-dependent initialization goes to plan, go back to the	 * beginning and try to install this freshly made tracepoint.	 */	if (fasttrap_tracepoint_init(p, probe, new_tp, pc) == 0)		goto again;	new_tp->ftt_ids = NULL;	new_tp->ftt_retids = NULL;	return (1);}static voidfasttrap_tracepoint_disable(proc_t *p, fasttrap_probe_t *probe, uint_t index){	fasttrap_bucket_t *bucket;	fasttrap_provider_t *provider = probe->ftp_prov;	fasttrap_tracepoint_t **pp, *tp;	fasttrap_id_t *id, **idp;	pid_t pid;	uintptr_t pc;	ASSERT(index < probe->ftp_ntps);	pid = probe->ftp_pid;	pc = probe->ftp_tps[index].fit_tp->ftt_pc;	ASSERT(probe->ftp_tps[index].fit_tp->ftt_pid == pid);	/*	 * Find the tracepoint and make sure that our id is one of the	 * ones registered with it.	 */	bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];	mutex_enter(&bucket->ftb_mtx);	for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {		if (tp->ftt_pid == pid && tp->ftt_pc == pc &&		    tp->ftt_prov == provider)			break;	}	/*	 * If we somehow lost this tracepoint, we're in a world of hurt.	 */	ASSERT(tp != NULL);	if (probe->ftp_type == DTFTP_RETURN ||	    probe->ftp_type == DTFTP_POST_OFFSETS) {		ASSERT(tp->ftt_retids != NULL);		idp = &tp->ftt_retids;	} else {		ASSERT(tp->ftt_ids != NULL);		idp = &tp->ftt_ids;	}	while ((*idp)->fti_probe != probe) {		idp = &(*idp)->fti_next;		ASSERT(*idp != NULL);	}	id = *idp;	*idp = id->fti_next;	membar_producer();	ASSERT(id->fti_probe == probe);	/*	 * If there are other registered enablings of this tracepoint, we're	 * all done, but if this was the last probe assocated with this	 * this tracepoint, we need to remove and free it.	 */	if (tp->ftt_ids != NULL || tp->ftt_retids != NULL) {		/*		 * If the current probe's tracepoint is in use, swap it		 * for an unused tracepoint.		 */		if (tp == probe->ftp_tps[index].fit_tp) {			fasttrap_probe_t *tmp_probe;			fasttrap_tracepoint_t **tmp_tp;			uint_t tmp_index;			if (tp->ftt_ids != NULL) {				tmp_probe = tp->ftt_ids->fti_probe;				tmp_index = FASTTRAP_ID_INDEX(tp->ftt_ids);				tmp_tp = &tmp_probe->ftp_tps[tmp_index].fit_tp;			} else {				tmp_probe = tp->ftt_retids->fti_probe;				tmp_index = FASTTRAP_ID_INDEX(tp->ftt_retids);				tmp_tp = &tmp_probe->ftp_tps[tmp_index].fit_tp;			}			ASSERT(*tmp_tp != NULL);			ASSERT(*tmp_tp != probe->ftp_tps[index].fit_tp);			ASSERT((*tmp_tp)->ftt_ids == NULL);			ASSERT((*tmp_tp)->ftt_retids == NULL);			probe->ftp_tps[index].fit_tp = *tmp_tp;			*tmp_tp = tp;		}		mutex_exit(&bucket->ftb_mtx);		/*		 * Tag the modified probe with the generation in which it was		 * changed.		 */		probe->ftp_gen = fasttrap_mod_gen;		return;	}	mutex_exit(&bucket->ftb_mtx);	/*	 * We can't safely remove the tracepoint from the set of active	 * tracepoints until we've actually removed the fasttrap instruction	 * from the process's text. We can, however, operate on this	 * tracepoint secure in the knowledge that no other thread is going to	 * be looking at it since we hold P_PR_LOCK on the process if it's	 * live or we hold the provider lock on the process if it's dead and	 * gone.	 */	/*	 * We only need to remove the actual instruction if we're looking	 * at an existing process	 */	if (p != NULL) {		/*		 * If we fail to restore the instruction we need to kill		 * this process since it's in a completely unrecoverable		 * state.		 */		if (fasttrap_tracepoint_remove(p, tp) != 0)			fasttrap_sigtrap(p, NULL, pc);		/*		 * Decrement the count of the number of tracepoints active		 * in the victim process.		 */		ASSERT(p->p_proc_flag & P_PR_LOCK);		p->p_dtrace_count--;	}	/*	 * Remove the probe from the hash table of active tracepoints.	 */	mutex_enter(&bucket->ftb_mtx);	pp = (fasttrap_tracepoint_t **)&bucket->ftb_data;	ASSERT(*pp != NULL);	while (*pp != tp) {		pp = &(*pp)->ftt_next;		ASSERT(*pp != NULL);	}	*pp = tp->ftt_next;	membar_producer();	mutex_exit(&bucket->ftb_mtx);	/*	 * Tag the modified probe with the generation in which it was changed.	 */	probe->ftp_gen = fasttrap_mod_gen;}typedef int fasttrap_probe_f(struct regs *);static voidfasttrap_enable_common(int *count, fasttrap_probe_f **fptr, fasttrap_probe_f *f,    fasttrap_probe_f **fptr2, fasttrap_probe_f *f2){	/*	 * We don't have to play the rw lock game here because we're	 * providing something rather than taking something away --	 * we can be sure that no threads have tried to follow this	 * function pointer yet.	 */	mutex_enter(&fasttrap_count_mtx);	if (*count == 0) {		ASSERT(*fptr == NULL);		*fptr = f;		if (fptr2 != NULL)			*fptr2 = f2;	}	ASSERT(*fptr == f);	ASSERT(fptr2 == NULL || *fptr2 == f2);	(*count)++;	mutex_exit(&fasttrap_count_mtx);}static voidfasttrap_disable_common(int *count, fasttrap_probe_f **fptr,    fasttrap_probe_f **fptr2){	ASSERT(MUTEX_HELD(&cpu_lock));	mutex_enter(&fasttrap_count_mtx);	(*count)--;	ASSERT(*count >= 0);	if (*count == 0) {		cpu_t *cur, *cpu = CPU;		for (cur = cpu->cpu_next_onln; cur != cpu;			cur = cur->cpu_next_onln) {			rw_enter(&cur->cpu_ft_lock, RW_WRITER);		}		*fptr = NULL;		if (fptr2 != NULL)			*fptr2 = NULL;		for (cur = cpu->cpu_next_onln; cur != cpu;			cur = cur->cpu_next_onln) {			rw_exit(&cur->cpu_ft_lock);		}	}	mutex_exit(&fasttrap_count_mtx);}/*ARGSUSED*/static voidfasttrap_enable(void *arg, dtrace_id_t id, void *parg){	/*	 * Enable the probe that corresponds to statically placed trace	 * points which have not explicitly been placed in the process's text	 * by the fasttrap provider.	 */	ASSERT(arg == NULL);	ASSERT(id == fasttrap_probe_id);	fasttrap_enable_common(&fasttrap_count,	    &dtrace_fasttrap_probe_ptr, fasttrap_probe, NULL, NULL);}/*ARGSUSED*/static voidfasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg){	fasttrap_probe_t *probe = parg;	proc_t *p;	int i;	ASSERT(probe != NULL);	ASSERT(!probe->ftp_enabled);	ASSERT(id == probe->ftp_id);	ASSERT(MUTEX_HELD(&cpu_lock));	/*	 * Increment the count of enabled probes on this probe's provider;	 * the provider can't go away while the probe still exists. We	 * must increment this even if we aren't able to properly enable	 * this probe.	 */	mutex_enter(&probe->ftp_prov->ftp_mtx);	probe->ftp_prov->ftp_rcount++;	mutex_exit(&probe->ftp_prov->ftp_mtx);	/*	 * Bail out if we can't find the process for this probe or its	 * provider is defunct (meaning it was valid in a previously exec'ed	 * incarnation of this address space). The provider can't go away	 * while we're in this code path.	 */	if (probe->ftp_prov->ftp_defunct ||	    (p = sprlock(probe->ftp_pid)) == NULL)		return;	ASSERT(!(p->p_flag & SVFORK));	mutex_exit(&p->p_lock);	/*	 * We have to enable the trap entry before any user threads have	 * the chance to execute the trap instruction we're about to place	 * in their process's text.	 */	fasttrap_enable_common(&fasttrap_pid_count,	    &dtrace_pid_probe_ptr, fasttrap_pid_probe,	    &dtrace_return_probe_ptr, fasttrap_return_probe);	/*	 * Enable all the tracepoints and add this probe's id to each	 * tracepoint's list of active probes.	 */	for (i = 0; i < probe->ftp_ntps; i++) {		if (fasttrap_tracepoint_enable(p, probe, i) != 0) {			/*			 * Back up and pull out all the tracepoints we've			 * created so far for this probe.			 */			while (--i >= 0) {				fasttrap_tracepoint_disable(p, probe, i);			}			mutex_enter(&p->p_lock);			sprunlock(p);			/*			 * Since we're not actually enabling this probe,			 * drop our reference on the trap table entry.			 */			fasttrap_disable_common(&fasttrap_pid_count,			    &dtrace_pid_probe_ptr, &dtrace_return_probe_ptr);			return;		}	}	mutex_enter(&p->p_lock);	sprunlock(p);	probe->ftp_enabled = 1;}/*ARGSUSED*/static voidfasttrap_disable(void *arg, dtrace_id_t id, void *parg){	/*	 * Disable the probe the corresponds to statically placed trace	 * points.	 */	ASSERT(arg == NULL);	ASSERT(id == fasttrap_probe_id);	ASSERT(MUTEX_HELD(&cpu_lock));	fasttrap_disable_common(&fasttrap_count, &dtrace_fasttrap_probe_ptr,	    NULL);}/*ARGSUSED*/static voidfasttrap_pid_disable(void *arg, dtrace_id_t id, void *parg){	fasttrap_probe_t *probe = parg;	fasttrap_provider_t *provider = probe->ftp_prov;	proc_t *p;	int i, whack = 0;	if (!probe->ftp_enabled) {		mutex_enter(&provider->ftp_mtx);		provider->ftp_rcount--;		ASSERT(provider->ftp_rcount >= 0);		mutex_exit(&provider->ftp_mtx);		return;	}	ASSERT(id == probe->ftp_id);	/*	 * We won't be able to acquire a /proc-esque lock on the process	 * iff the process is dead and gone. In this case, we rely on the	 * provider lock as a point of mutual exclusion to prevent other	 * DTrace consumers from disabling this probe.	 */	if ((p = sprlock(probe->ftp_pid)) != NULL) {		ASSERT(!(p->p_flag & SVFORK));		mutex_exit(&p->p_lock);	}	mutex_enter(&provider->ftp_mtx);	/*	 * Disable all the associated tracepoints.	 */	for (i = 0; i < probe->ftp_ntps; i++) {		fasttrap_tracepoint_disable(p, probe, i);	}	ASSERT(provider->ftp_rcount > 0);	provider->ftp_rcount--;	if (p != NULL) {		/*		 * Even though we may not be able to remove it entirely, we		 * mark this defunct provider to get a chance to remove some		 * of the associated probes.		 */		if (provider->ftp_defunct && !provider->ftp_marked)			whack = provider->ftp_marked = 1;		mutex_exit(&provider->ftp_mtx);		mutex_enter(&p->p_lock);

⌨️ 快捷键说明

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