void dt_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 */ }
void dt_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); }
void dt_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) { dpr->dpr_stop &= ~DT_PROC_STOP_IDLE; (void) pthread_cond_broadcast(&dpr->dpr_cv); } (void) pthread_mutex_unlock(&dpr->dpr_lock); }
static void dt_proc_destroy(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; dt_proc_notify_t *npr, **npp; int rflag; assert(dpr != NULL); /* * If neither PR_KLC nor PR_RLC is set, then the process is stopped by * an external debugger and we were waiting in dt_proc_waitrun(). * Leave the process in this condition using PRELEASE_HANG. */ printf("dt_proc_destroy flags=%d\n", Pstatus(dpr->dpr_proc)->pr_flags); if (!(Pstatus(dpr->dpr_proc)->pr_flags & (PR_KLC | PR_RLC))) { dt_dprintf("abandoning pid %d\n", (int)dpr->dpr_pid); rflag = PRELEASE_HANG; } else { dt_dprintf("releasing pid %d\n", (int)dpr->dpr_pid); rflag = 0; /* apply kill or run-on-last-close */ } if (dpr->dpr_tid) { /* * Set the dpr_quit flag to tell the daemon thread to exit. We * send it a SIGCANCEL to poke it out of PCWSTOP or any other * long-term /proc system call. Our daemon threads have POSIX * cancellation disabled, so EINTR will be the only effect. We * then wait for dpr_done to indicate the thread has exited. * * We can't use pthread_kill() to send SIGCANCEL because the * interface forbids it and we can't use pthread_cancel() * because with cancellation disabled it won't actually * send SIGCANCEL to the target thread, so we use _lwp_kill() * to do the job. This is all built on evil knowledge of * the details of the cancellation mechanism in libc. */ (void) pthread_mutex_lock(&dpr->dpr_lock); dpr->dpr_quit = B_TRUE; #if defined(sun) (void) _lwp_kill(dpr->dpr_tid, SIGCANCEL); #else (void) pthread_kill(dpr->dpr_tid, SIGUSR1); #endif /* * If the process is currently idling in dt_proc_stop(), re- * enable breakpoints and poke it into running again. */ if (dpr->dpr_stop & DT_PROC_STOP_IDLE) { dt_proc_bpenable(dpr); dpr->dpr_stop &= ~DT_PROC_STOP_IDLE; (void) pthread_cond_broadcast(&dpr->dpr_cv); } while (!dpr->dpr_done) (void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock); (void) pthread_mutex_unlock(&dpr->dpr_lock); } /* * Before we free the process structure, remove this dt_proc_t from the * lookup hash, and then walk the dt_proc_hash_t's notification list * and remove this dt_proc_t if it is enqueued. */ (void) pthread_mutex_lock(&dph->dph_lock); (void) dt_proc_lookup(dtp, P, B_TRUE); npp = &dph->dph_notify; while ((npr = *npp) != NULL) { if (npr->dprn_dpr == dpr) { *npp = npr->dprn_next; dt_free(dtp, npr); } else { npp = &npr->dprn_next; } } (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); }
int dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb) { char provname[DTRACE_PROVNAMELEN]; struct ps_prochandle *P; dt_proc_t *dpr; pid_t pid; int err = 0; assert(pcb != NULL); if ((pid = dt_pid_get_pid(pdp, dtp, pcb, NULL)) == -1) return (-1); if (dtp->dt_ftfd == -1) { if (dtp->dt_fterr == ENOENT) { (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV, "pid provider is not installed on this system"); } else { (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV, "pid provider is not available: %s", strerror(dtp->dt_fterr)); } return (-1); } (void) snprintf(provname, sizeof (provname), "pid%d", (int)pid); if (gmatch(provname, pdp->dtpd_provider) != 0) { if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0)) == NULL) { (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB, "failed to grab process %d", (int)pid); return (-1); } dpr = dt_proc_lookup(dtp, P, 0); assert(dpr != NULL); (void) pthread_mutex_lock(&dpr->dpr_lock); if ((err = dt_pid_create_pid_probes(pdp, dtp, pcb, dpr)) == 0) { /* * Alert other retained enablings which may match * against the newly created probes. */ (void) dt_ioctl(dtp, DTRACEIOC_ENABLE, NULL); } (void) pthread_mutex_unlock(&dpr->dpr_lock); dt_proc_release(dtp, P); } /* * If it's not strictly a pid provider, we might match a USDT provider. */ if (strcmp(provname, pdp->dtpd_provider) != 0) { if ((P = dt_proc_grab(dtp, pid, 0, 1)) == NULL) { (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB, "failed to grab process %d", (int)pid); return (-1); } dpr = dt_proc_lookup(dtp, P, 0); assert(dpr != NULL); (void) pthread_mutex_lock(&dpr->dpr_lock); if (!dpr->dpr_usdt) { err = dt_pid_create_usdt_probes(pdp, dtp, pcb, dpr); dpr->dpr_usdt = B_TRUE; } (void) pthread_mutex_unlock(&dpr->dpr_lock); dt_proc_release(dtp, P); } return (err ? -1 : 0); }