dt_proc.c

来自「Sun Solaris 10 中的 DTrace 组件的源代码。请参看: htt」· C语言 代码 · 共 1,011 行 · 第 1/3 页

C
1,011
字号
	for (npr = *npp; npr != NULL; npr = npr->dpr_notify) {		if (npr != dpr)			npp = &npr->dpr_notify;		else			break;	}	if (npr != NULL) {		*npp = npr->dpr_notify;		npr->dpr_notify = NULL;	}	(void) pthread_mutex_unlock(&dph->dph_lock);	/*	 * Remove the dt_proc_list from the LRU list, release the underlying	 * libproc handle, and free our dt_proc_t data structure.	 */	if (dpr->dpr_cacheable) {		assert(dph->dph_lrucnt != 0);		dph->dph_lrucnt--;	}	dt_list_delete(&dph->dph_lrulist, dpr);	Prelease(dpr->dpr_proc, rflag);	dt_free(dtp, dpr);}static intdt_proc_create_thread(dt_proc_t *dpr, uint_t stop){	sigset_t nset, oset;	pthread_attr_t a;	int err;	(void) pthread_mutex_lock(&dpr->dpr_lock);	dpr->dpr_stop |= stop; /* set bit for initial rendezvous */	(void) pthread_attr_init(&a);	(void) pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);	(void) sigfillset(&nset);	(void) sigdelset(&nset, SIGABRT);	/* unblocked for assert() */	(void) sigdelset(&nset, SIGCANCEL);	/* see dt_proc_destroy() */	(void) pthread_sigmask(SIG_SETMASK, &nset, &oset);	err = pthread_create(&dpr->dpr_tid, &a, dt_proc_control, dpr);	(void) pthread_sigmask(SIG_SETMASK, &oset, NULL);	/*	 * If the control thread was created, then wait on dpr_cv for either	 * dpr_done to be set (the victim died or the control thread failed)	 * or DT_PROC_STOP_IDLE to be set, indicating that the victim is now	 * stopped by /proc and the control thread is at the rendezvous event.	 * On success, we return with the process and control thread stopped:	 * the caller can then apply dt_proc_continue() to resume both.	 */	if (err == 0) {		while (!dpr->dpr_done && !(dpr->dpr_stop & DT_PROC_STOP_IDLE))			(void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock);		/*		 * If dpr_done is set, the control thread aborted before it		 * reached the rendezvous event.  This is either due to PS_LOST		 * or PS_UNDEAD (i.e. the process died).  We try to provide a		 * small amount of useful information to help figure it out.		 */		if (dpr->dpr_done) {			const psinfo_t *prp = Ppsinfo(dpr->dpr_proc);			int stat = prp ? prp->pr_wstat : 0;			int pid = dpr->dpr_pid;			if (Pstate(dpr->dpr_proc) == PS_LOST) {				(void) dt_proc_error(dpr->dpr_hdl, dpr,				    "failed to control pid %d: process exec'd "				    "set-id or unobservable program\n", pid);			} else if (WIFSIGNALED(stat)) {				(void) dt_proc_error(dpr->dpr_hdl, dpr,				    "failed to control pid %d: process died "				    "from signal %d\n", pid, WTERMSIG(stat));			} else {				(void) dt_proc_error(dpr->dpr_hdl, dpr,				    "failed to control pid %d: process exited "				    "with status %d\n", pid, WEXITSTATUS(stat));			}			err = ESRCH; /* cause grab() or create() to fail */		} else {			/*			 * Disable breakpoints while the process is stopped so			 * the pid provider can correctly disassemble all			 * functions.			 */			dt_proc_bpdisable(dpr);		}	} else {		(void) dt_proc_error(dpr->dpr_hdl, dpr,		    "failed to create control thread for process-id %d: %s\n",		    (int)dpr->dpr_pid, strerror(err));	}	(void) pthread_mutex_unlock(&dpr->dpr_lock);	(void) pthread_attr_destroy(&a);	return (err);}struct ps_prochandle *dt_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv){	dt_proc_hash_t *dph = dtp->dt_procs;	dt_proc_t *dpr;	int err;	if ((dpr = dt_zalloc(dtp, sizeof (dt_proc_t))) == NULL)		return (NULL); /* errno is set for us */	(void) pthread_mutex_init(&dpr->dpr_lock, NULL);	(void) pthread_cond_init(&dpr->dpr_cv, NULL);	if ((dpr->dpr_proc = Pcreate(file, argv, &err, NULL, 0)) == NULL) {		return (dt_proc_error(dtp, dpr,		    "failed to execute %s: %s\n", file, Pcreate_error(err)));	}	dpr->dpr_hdl = dtp;	dpr->dpr_pid = Pstatus(dpr->dpr_proc)->pr_pid;	(void) Punsetflags(dpr->dpr_proc, PR_RLC);	(void) Psetflags(dpr->dpr_proc, PR_KLC);	if (dt_proc_create_thread(dpr, dtp->dt_prcmode) != 0)		return (NULL); /* dt_proc_error() has been called for us */	dpr->dpr_hash = dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)];	dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)] = dpr;	dt_list_prepend(&dph->dph_lrulist, dpr);	dt_dprintf("created pid %d\n", (int)dpr->dpr_pid);	dpr->dpr_refs++;	return (dpr->dpr_proc);}struct ps_prochandle *dt_proc_grab(dtrace_hdl_t *dtp, pid_t pid, int flags, int nomonitor){	dt_proc_hash_t *dph = dtp->dt_procs;	uint_t h = pid & (dph->dph_hashlen - 1);	dt_proc_t *dpr, *opr;	int err;	/*	 * Search the hash table for the pid.  If it is already grabbed or	 * created, move the handle to the front of the lrulist, increment	 * the reference count, and return the existing ps_prochandle.	 */	for (dpr = dph->dph_hash[h]; dpr != NULL; dpr = dpr->dpr_hash) {		if (dpr->dpr_pid == pid) {			dt_dprintf("grabbed pid %d (cached)\n", (int)pid);			dt_list_delete(&dph->dph_lrulist, dpr);			dt_list_prepend(&dph->dph_lrulist, dpr);			dpr->dpr_refs++;			return (dpr->dpr_proc);		}	}	if ((dpr = dt_zalloc(dtp, sizeof (dt_proc_t))) == NULL)		return (NULL); /* errno is set for us */	(void) pthread_mutex_init(&dpr->dpr_lock, NULL);	(void) pthread_cond_init(&dpr->dpr_cv, NULL);	if ((dpr->dpr_proc = Pgrab(pid, flags, &err)) == NULL) {		return (dt_proc_error(dtp, dpr,		    "failed to grab pid %d: %s\n", (int)pid, Pgrab_error(err)));	}	dpr->dpr_hdl = dtp;	dpr->dpr_pid = pid;	(void) Punsetflags(dpr->dpr_proc, PR_KLC);	(void) Psetflags(dpr->dpr_proc, PR_RLC);	/*	 * If we are attempting to grab the process without a monitor	 * thread, then mark the process as cacheable.  If we're currently	 * caching more process handles than dph_lrulim permits, attempt to	 * find the least-recently-used handle that is currently	 * unreferenced and release it from the cache.  Otherwise we are	 * grabbing the process for control: create a control thread for	 * this process and store its ID in dpr->dpr_tid.	 */	if (nomonitor || (flags & PGRAB_RDONLY)) {		if (dph->dph_lrucnt >= dph->dph_lrulim) {			for (opr = dt_list_prev(&dph->dph_lrulist);			    opr != NULL; opr = dt_list_prev(opr)) {				if (opr->dpr_cacheable && opr->dpr_refs == 0) {					dt_proc_destroy(dtp, opr->dpr_proc);					break;				}			}		}		if (flags & PGRAB_RDONLY) {			dpr->dpr_cacheable = B_TRUE;			dph->dph_lrucnt++;		}	} else if (dt_proc_create_thread(dpr, DT_PROC_STOP_GRAB) != 0)		return (NULL); /* dt_proc_error() has been called for us */	dpr->dpr_hash = dph->dph_hash[h];	dph->dph_hash[h] = dpr;	dt_list_prepend(&dph->dph_lrulist, dpr);	dt_dprintf("grabbed pid %d\n", (int)pid);	dpr->dpr_refs++;	return (dpr->dpr_proc);}voiddt_proc_release(dtrace_hdl_t *dtp, struct ps_prochandle *P){	dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);	dt_proc_hash_t *dph = dtp->dt_procs;	assert(dpr != NULL);	assert(dpr->dpr_refs != 0);	if (--dpr->dpr_refs == 0 &&	    (!dpr->dpr_cacheable || dph->dph_lrucnt > dph->dph_lrulim))		dt_proc_destroy(dtp, P);}voiddt_proc_continue(dtrace_hdl_t *dtp, struct ps_prochandle *P){	dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);	(void) pthread_mutex_lock(&dpr->dpr_lock);	if (dpr->dpr_stop & DT_PROC_STOP_IDLE) {		/*		 * Breakpoints are disabled while the process is stopped so		 * the pid provider can correctly disassemble all functions.		 */		dt_proc_bpenable(dpr);		dpr->dpr_stop &= ~DT_PROC_STOP_IDLE;		(void) pthread_cond_broadcast(&dpr->dpr_cv);	}	(void) pthread_mutex_unlock(&dpr->dpr_lock);}voiddt_proc_lock(dtrace_hdl_t *dtp, struct ps_prochandle *P){	dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);	int err = pthread_mutex_lock(&dpr->dpr_lock);	assert(err == 0); /* check for recursion */}voiddt_proc_unlock(dtrace_hdl_t *dtp, struct ps_prochandle *P){	dt_proc_t *dpr = dt_proc_lookup(dtp, P, B_FALSE);	int err = pthread_mutex_unlock(&dpr->dpr_lock);	assert(err == 0); /* check for unheld lock */}voiddt_proc_hash_create(dtrace_hdl_t *dtp){	if ((dtp->dt_procs = dt_zalloc(dtp, sizeof (dt_proc_hash_t) +	    sizeof (dt_proc_t *) * _dtrace_pidbuckets - 1)) != NULL) {		(void) pthread_mutex_init(&dtp->dt_procs->dph_lock, NULL);		(void) pthread_cond_init(&dtp->dt_procs->dph_cv, NULL);		dtp->dt_procs->dph_hashlen = _dtrace_pidbuckets;		dtp->dt_procs->dph_lrulim = _dtrace_pidlrulim;	}}voiddt_proc_hash_destroy(dtrace_hdl_t *dtp){	dt_proc_hash_t *dph = dtp->dt_procs;	dt_proc_t *dpr;	while ((dpr = dt_list_next(&dph->dph_lrulist)) != NULL)		dt_proc_destroy(dtp, dpr->dpr_proc);	dtp->dt_procs = NULL;	dt_free(dtp, dph);}struct ps_prochandle *dtrace_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv){	dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");	struct ps_prochandle *P = dt_proc_create(dtp, file, argv);	if (P != NULL && idp != NULL && idp->di_id == 0)		idp->di_id = Pstatus(P)->pr_pid; /* $target = created pid */	return (P);}struct ps_prochandle *dtrace_proc_grab(dtrace_hdl_t *dtp, pid_t pid, int flags){	dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");	struct ps_prochandle *P = dt_proc_grab(dtp, pid, flags, 0);	if (P != NULL && idp != NULL && idp->di_id == 0)		idp->di_id = pid; /* $target = grabbed pid */	return (P);}voiddtrace_proc_release(dtrace_hdl_t *dtp, struct ps_prochandle *P){	dt_proc_release(dtp, P);}voiddtrace_proc_continue(dtrace_hdl_t *dtp, struct ps_prochandle *P){	dt_proc_continue(dtp, P);}

⌨️ 快捷键说明

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