/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#include <sys/sysmacros.h>
#include <sys/schedctl.h>
#if defined(__sparc)
#endif
static int pr_clearsig(prnode_t *);
static int pr_clearflt(prnode_t *);
static void unpauselwps(proc_t *);
typedef union {
#if defined(__sparc)
#endif
} arg_t;
static size_t
{
int ngrp;
switch (cmd) {
case PCNULL:
case PCSTOP:
case PCDSTOP:
case PCWSTOP:
case PCCSIG:
case PCCFAULT:
break;
case PCSSIG:
break;
case PCTWSTOP:
size += sizeof (long);
break;
case PCKILL:
case PCUNKILL:
case PCNICE:
size += sizeof (long);
break;
case PCRUN:
case PCSET:
case PCUNSET:
break;
case PCSVADDR:
break;
case PCSTRACE:
case PCSHOLD:
break;
case PCSFAULT:
break;
case PCSENTRY:
case PCSEXIT:
break;
case PCSREG:
case PCAGENT:
size += sizeof (prgregset_t);
break;
case PCSFPREG:
size += sizeof (prfpregset_t);
break;
#if defined(__sparc)
case PCSXREG:
size += sizeof (prxregset_t);
break;
case PCSASRS:
break;
#endif
case PCWATCH:
break;
case PCREAD:
case PCWRITE:
break;
case PCSCRED:
break;
case PCSCREDX:
/*
* We cannot derefence the pr_ngroups fields if it
* we don't have enough data.
*/
return (0);
return (0);
/* The result can be smaller than sizeof (prcred_t) */
break;
case PCSPRIV:
else
return (0);
break;
case PCSZONE:
size += sizeof (long);
break;
default:
return (0);
}
/* Round up to a multiple of long, unless exact amount written */
if (rnd != 0)
}
return (0);
return (size);
}
/*
* Control operations (lots).
*/
int
{
#define MY_BUFFER_SIZE \
long *bufp;
int error;
int locked = 0;
/*
* Read several commands in one gulp.
*/
if (resid) { /* move incomplete command to front of buffer */
long *tail;
break;
do {
} while ((resid -= sizeof (long)) != 0);
}
return (error);
do { /* loop over commands in buffer */
if (size == 0) /* incomplete or invalid command */
break;
/*
* Perform the specified control operation.
*/
if (!locked) {
return (error);
locked = 1;
}
locked = 0;
else
return (error);
}
if (locked) {
locked = 0;
}
}
}
static int
{
proc_t *p;
int unlocked;
int error = 0;
return (0);
/* System processes defy control. */
return (EBUSY);
}
switch (cmd) {
default:
break;
case PCSTOP: /* direct process or lwp to stop and wait for stop */
case PCDSTOP: /* direct process or lwp to stop, don't wait */
case PCWSTOP: /* wait for process or lwp to stop */
case PCTWSTOP: /* wait for process or lwp to stop, with timeout */
{
/*
* Can't apply to a system process.
*/
break;
}
break;
/*
* If an lwp is waiting for itself or its process,
* don't wait. The stopped lwp would never see the
* fact that it is stopped.
*/
break;
}
return (error);
break;
}
case PCRUN: /* make lwp or process runnable */
break;
case PCSTRACE: /* set signal trace mask */
break;
case PCSSIG: /* set current signal */
return (-1);
}
break;
case PCKILL: /* send signal */
return (-1);
}
break;
case PCUNKILL: /* delete a pending signal */
break;
case PCNICE: /* set nice priority */
break;
case PCSENTRY: /* set syscall entry bit mask */
case PCSEXIT: /* set syscall exit bit mask */
break;
case PCSET: /* set process flags */
break;
case PCUNSET: /* unset process flags */
break;
case PCSREG: /* set general registers */
{
thread_unlock(t);
} else {
thread_unlock(t);
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
break;
}
case PCSFPREG: /* set floating-point registers */
break;
case PCSXREG: /* set extra registers */
#if defined(__sparc)
#else
#endif
break;
#if defined(__sparc)
case PCSASRS: /* set ancillary state registers */
break;
#endif
case PCSVADDR: /* set virtual address at which to resume */
break;
case PCSHOLD: /* set signal-hold mask */
break;
case PCSFAULT: /* set mask of traced faults */
break;
case PCCSIG: /* clear current signal */
break;
case PCCFAULT: /* clear current fault */
break;
case PCWATCH: /* set or clear watched areas */
return (error);
break;
case PCAGENT: /* create the /proc agent lwp in the target process */
return (error);
break;
case PCREAD: /* read from the address space */
break;
case PCWRITE: /* write to the address space */
break;
case PCSCRED: /* set the process credentials */
case PCSCREDX:
break;
case PCSPRIV: /* set the process privileges */
break;
case PCSZONE: /* set the process's zoneid credentials */
break;
}
if (error)
return (error);
}
#ifdef _SYSCALL32_IMPL
typedef union {
#if defined(__sparc)
#endif
} arg32_t;
/*
* Note that while ctlsize32() can use argp, it must do so only in a way
* that assumes 32-bit rather than 64-bit alignment as argp is a pointer
* to an array of 32-bit values and only 32-bit alignment is ensured.
*/
static size_t
{
int ngrp;
switch (cmd) {
case PCNULL:
case PCSTOP:
case PCDSTOP:
case PCWSTOP:
case PCCSIG:
case PCCFAULT:
break;
case PCSSIG:
size += sizeof (siginfo32_t);
break;
case PCTWSTOP:
break;
case PCKILL:
case PCUNKILL:
case PCNICE:
break;
case PCRUN:
case PCSET:
case PCUNSET:
break;
case PCSVADDR:
break;
case PCSTRACE:
case PCSHOLD:
break;
case PCSFAULT:
break;
case PCSENTRY:
case PCSEXIT:
break;
case PCSREG:
case PCAGENT:
size += sizeof (prgregset32_t);
break;
case PCSFPREG:
size += sizeof (prfpregset32_t);
break;
#if defined(__sparc)
case PCSXREG:
size += sizeof (prxregset_t);
break;
#endif
case PCWATCH:
size += sizeof (prwatch32_t);
break;
case PCREAD:
case PCWRITE:
size += sizeof (priovec32_t);
break;
case PCSCRED:
size += sizeof (prcred32_t);
break;
case PCSCREDX:
/*
* We cannot derefence the pr_ngroups fields if it
* we don't have enough data.
*/
return (0);
return (0);
/* The result can be smaller than sizeof (prcred32_t) */
break;
case PCSPRIV:
else
return (0);
break;
case PCSZONE:
break;
default:
return (0);
}
/* Round up to a multiple of int32_t */
if (rnd != 0)
return (0);
return (size);
}
/*
* Control operations (lots).
*/
int
{
#define MY_BUFFER_SIZE32 \
int error;
int locked = 0;
/*
* Read several commands in one gulp.
*/
if (resid) { /* move incomplete command to front of buffer */
break;
do {
}
return (error);
do { /* loop over commands in buffer */
if (size == 0) /* incomplete or invalid command */
break;
/*
* Perform the specified control operation.
*/
if (!locked) {
return (error);
locked = 1;
}
/*
* Since some members of the arg32_t union contain
* 64-bit values (which must be 64-bit aligned), we
* can't simply pass a pointer to the structure as
* it may be unaligned. Note that we do pass the
* potentially unaligned structure to ctlsize32()
* above, but that uses it a way that makes no
* assumptions about alignment.
*/
locked = 0;
else
return (error);
}
if (locked) {
locked = 0;
}
}
}
static int
{
proc_t *p;
int unlocked;
int error = 0;
return (0);
return (EBUSY);
}
switch (cmd) {
default:
break;
case PCSTOP: /* direct process or lwp to stop and wait for stop */
case PCDSTOP: /* direct process or lwp to stop, don't wait */
case PCWSTOP: /* wait for process or lwp to stop */
case PCTWSTOP: /* wait for process or lwp to stop, with timeout */
{
/*
* Can't apply to a system process.
*/
break;
}
break;
/*
* If an lwp is waiting for itself or its process,
* don't wait. The lwp will never see the fact that
* itself is stopped.
*/
break;
}
return (error);
break;
}
case PCRUN: /* make lwp or process runnable */
break;
case PCSTRACE: /* set signal trace mask */
break;
case PCSSIG: /* set current signal */
if (PROCESS_NOT_32BIT(p))
else {
return (-1);
}
}
break;
case PCKILL: /* send signal */
return (-1);
}
break;
case PCUNKILL: /* delete a pending signal */
break;
case PCNICE: /* set nice priority */
break;
case PCSENTRY: /* set syscall entry bit mask */
case PCSEXIT: /* set syscall exit bit mask */
break;
case PCSET: /* set process flags */
break;
case PCUNSET: /* unset process flags */
break;
case PCSREG: /* set general registers */
if (PROCESS_NOT_32BIT(p))
else {
thread_unlock(t);
} else {
thread_unlock(t);
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
}
break;
case PCSFPREG: /* set floating-point registers */
if (PROCESS_NOT_32BIT(p))
else
break;
case PCSXREG: /* set extra registers */
#if defined(__sparc)
if (PROCESS_NOT_32BIT(p))
else
#else
#endif
break;
case PCSVADDR: /* set virtual address at which to resume */
if (PROCESS_NOT_32BIT(p))
else
break;
case PCSHOLD: /* set signal-hold mask */
break;
case PCSFAULT: /* set mask of traced faults */
break;
case PCCSIG: /* clear current signal */
break;
case PCCFAULT: /* clear current fault */
break;
case PCWATCH: /* set or clear watched areas */
if (PROCESS_NOT_32BIT(p))
else {
return (error);
}
break;
case PCAGENT: /* create the /proc agent lwp in the target process */
if (PROCESS_NOT_32BIT(p))
else {
thread_unlock(t);
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
return (error);
}
break;
case PCREAD: /* read from the address space */
case PCWRITE: /* write to the address space */
else {
}
break;
case PCSCRED: /* set the process credentials */
case PCSCREDX:
{
/*
* All the fields in these structures are exactly the
* same and so the structures are compatible. In case
* this ever changes, we catch this with the ASSERT
* below.
*/
#ifndef __lint
#endif
break;
}
case PCSPRIV: /* set the process privileges */
break;
case PCSZONE: /* set the process's zoneid */
break;
}
if (error)
return (error);
}
#endif /* _SYSCALL32_IMPL */
/*
* Returns with the thread locked via thread_lock(t).
*/
{
kthread_t *t;
t = pcp->prc_thread;
thread_lock(t);
} else {
t = prchoose(p); /* returns locked thread */
}
return (t);
}
/*
* Direct the process or lwp to stop.
*/
void
{
kthread_t *t;
/*
* If already stopped, do nothing; otherwise flag
* it to be stopped the next time it tries to run.
* If sleeping at interruptible priority, set it
* running so it will stop within cv_wait_sig().
*
* Take care to cooperate with jobcontrol: if an lwp
* is stopped due to the default action of a jobcontrol
* stop signal, flag it to be stopped the next time it
* starts due to a SIGCONT signal.
*/
t = pcp->prc_thread;
else
t = p->p_tlist;
do {
int notify;
notify = 0;
thread_lock(t);
if (!ISTOPPED(t)) {
t->t_proc_flag |= TP_PRSTOP;
}
/* Move the thread from wait queue to run queue */
if (ISWAITING(t))
setrun_locked(t);
if (ISWAKEABLE(t)) {
setrun_locked(t);
else if (!VSTOPPED(t)) {
/*
* Mark it virtually stopped.
*/
t->t_proc_flag |= TP_PRVSTOP;
notify = 1;
}
}
/*
* force the thread into the kernel
* if it is not already there.
*/
prpokethread(t);
thread_unlock(t);
if (notify &&
break;
/*
* We do this just in case the thread we asked
* to stop is in holdlwps() (called from cfork()).
*/
cv_broadcast(&p->p_holdlwps);
}
/*
* Sleep until the lwp stops, but cooperate with
* jobcontrol: Don't wake up if the lwp is stopped
* due to the default action of a jobcontrol stop signal.
* If this is the process file descriptor, sleep
* until all of the process's lwps stop.
*/
int
{
int timecheck = 0;
kthread_t *t;
int error;
if (timeo > 0) { /* millisecond timeout */
/*
* Determine the precise future time of the requested timeout.
*/
gethrestime(&now);
}
t = pcp->prc_thread;
thread_lock(t);
thread_unlock(t);
if (error) /* -1 is timeout */
return (error);
return (error);
thread_lock(t);
}
thread_unlock(t);
} else { /* process file descriptor */
t = prchoose(p); /* returns locked thread */
thread_unlock(t);
if (error) /* -1 is timeout */
return (error);
return (error);
t = prchoose(p); /* returns locked t */
}
thread_unlock(t);
}
return (0);
}
int
{
kthread_t *t;
/*
* Cannot set an lwp running if it is not stopped.
* Also, no lwp other than the /proc agent lwp can
* be set running so long as the /proc agent lwp exists.
*/
!(t->t_proc_flag & TP_PRSTOP)) ||
thread_unlock(t);
return (EBUSY);
}
thread_unlock(t);
return (EINVAL);
/*
* Discard current siginfo_t, if any.
*/
lwp->lwp_cursig = 0;
lwp->lwp_extsig = 0;
if (lwp->lwp_curinfo) {
}
}
lwp->lwp_curflt = 0;
/*
* We can't hold p->p_lock when we touch the lwp's registers.
* It may be swapped out and we will get a page fault.
*/
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
t->t_proc_flag |= TP_PRSTOP;
}
thread_lock(t);
/*
* Here, we are dealing with a single lwp.
*/
if (ISTOPPED(t)) {
t->t_schedflag |= TS_PSTART;
t->t_dtrace_stop = 0;
setrun_locked(t);
t->t_proc_flag &=
setrun_locked(t);
t->t_proc_flag &=
}
thread_unlock(t);
} else {
/*
* Here, we are dealing with the whole process.
*/
if (ISTOPPED(t)) {
/*
* The representative lwp is stopped on an event
* of interest. We demote it to PR_REQUESTED and
* choose another representative lwp. If the new
* representative lwp is not stopped on an event of
* interest (other than PR_REQUESTED), we set the
* whole process running, else we leave the process
* stopped showing the next event of interest.
*/
t->t_whystop == PR_SYSENTRY &&
t->t_whatstop == SYS_lwp_exit)
tx = t; /* remember the exiting lwp */
t->t_whystop = PR_REQUESTED;
t->t_whatstop = 0;
thread_unlock(t);
t = prchoose(p); /* returns locked t */
if (VSTOPPED(t) ||
t->t_whystop == PR_REQUESTED) {
thread_unlock(t);
allsetrun(p);
} else {
thread_unlock(t);
/*
* As a special case, if the old representative
* lwp was stopped on entry to _lwp_exit()
* (and we are not aborting the system call),
* we set the old representative lwp running.
* We do this so that the next process stop
* will find the exiting lwp gone.
*/
t->t_dtrace_stop = 0;
}
}
} else {
/*
* No event of interest; set all of the lwps running.
*/
t->t_proc_flag &=
setrun_locked(t);
}
thread_unlock(t);
allsetrun(p);
}
}
return (0);
}
/*
* Return EINTR for an interruption, -1 for timeout, else 0.
*/
int
int timecheck)
{
int rval;
switch (rval) {
case 0:
return (EINTR);
case -1:
return (-1);
default:
return (0);
}
}
/*
* Make all threads in the process runnable.
*/
void
{
kthread_t *t;
do {
thread_lock(t);
if (ISTOPPED(t)) {
t->t_schedflag |= TS_PSTART;
t->t_dtrace_stop = 0;
setrun_locked(t);
}
thread_unlock(t);
}
}
/*
* Wait for the process to die.
* We do this after sending SIGKILL because we know it will
* die soon and we want subsequent operations to return ENOENT.
*/
void
{
proc_t *p;
break;
}
}
static void
{
if (!sigisempty(&p->p_sigmask))
p->p_proc_flag |= P_PR_TRACE;
p->p_proc_flag &= ~P_PR_TRACE;
}
}
int
{
kthread_t *t;
int error = 0;
thread_unlock(t);
/* Zero allowed here */
/* "can't happen", but just in case */
lwp->lwp_extsig = 0;
/*
* Discard current siginfo_t, if any.
*/
if (lwp->lwp_curinfo) {
}
} else {
/* drop p_lock to do kmem_alloc(KM_SLEEP) */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
else
/*
* Copy contents of info to current siginfo_t.
*/
/*
* Prevent contents published by si_zoneid-unaware /proc
* consumers from being incorrectly filtered. Because
* an uninitialized si_zoneid is the same as
* GLOBAL_ZONEID, this means that you can't pr_setsig a
* process in a non-global zone with a siginfo which
* appears to come from the global zone.
*/
/*
* Side-effects for SIGKILL and jobcontrol signals.
*/
p->p_flag &= ~SEXTKILLED;
do {
}
do {
}
}
thread_lock(t);
if (ISWAKEABLE(t) || ISWAITING(t)) {
setrun_locked(t);
/* If SIGKILL, set stopped lwp running */
p->p_stopsig = 0;
t->t_dtrace_stop = 0;
setrun_locked(t);
}
thread_unlock(t);
/*
* More jobcontrol side-effects.
*/
p->p_stopsig = 0;
do {
}
}
}
return (error);
}
int
{
return (EINVAL);
return (0);
}
int
{
return (EINVAL);
else
if (infop)
return (0);
}
int
{
kthread_t *t;
int err;
int error = 0;
t = p->p_tlist;
do {
if (error == 0)
return (error);
}
void
{
if (entry) {
} else {
}
p->p_proc_flag |= P_PR_TRACE;
set_proc_sys(p); /* set pre and post-sys flags */
} else {
if (sigisempty(&p->p_sigmask) &&
p->p_proc_flag &= ~P_PR_TRACE;
}
}
#define ALLFLAGS \
int
{
return (EBUSY);
return (EINVAL);
p->p_proc_flag |= P_PR_FORK;
p->p_proc_flag |= P_PR_RUNLCL;
p->p_proc_flag |= P_PR_KILLCL;
p->p_proc_flag |= P_PR_ASYNC;
p->p_proc_flag |= P_PR_BPTADJ;
p->p_proc_flag |= P_PR_PTRACE;
/* ptraced process must die if parent dead */
if (p->p_ppid == 1)
}
return (0);
}
int
{
return (EBUSY);
return (EINVAL);
p->p_proc_flag &= ~P_PR_FORK;
p->p_proc_flag &= ~P_PR_RUNLCL;
p->p_proc_flag &= ~P_PR_KILLCL;
p->p_proc_flag &= ~P_PR_ASYNC;
p->p_proc_flag &= ~P_PR_BPTADJ;
disable_msacct(p);
p->p_proc_flag &= ~P_PR_PTRACE;
return (0);
}
static int
{
thread_unlock(t);
return (EBUSY);
}
if (!prhasfp()) {
thread_unlock(t);
return (EINVAL); /* No FP support */
}
/* drop p_lock while touching the lwp's stack */
thread_unlock(t);
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
return (0);
}
#ifdef _SYSCALL32_IMPL
static int
{
thread_unlock(t);
return (EBUSY);
}
if (!prhasfp()) {
thread_unlock(t);
return (EINVAL); /* No FP support */
}
/* drop p_lock while touching the lwp's stack */
thread_unlock(t);
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
return (0);
}
#endif /* _SYSCALL32_IMPL */
#if defined(__sparc)
/* ARGSUSED */
static int
{
thread_unlock(t);
return (EBUSY);
}
thread_unlock(t);
if (!prhasx(p))
return (EINVAL); /* No extra register support */
/* drop p_lock while touching the lwp's stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
return (0);
}
static int
{
thread_unlock(t);
return (EBUSY);
}
thread_unlock(t);
/* drop p_lock while touching the lwp's stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
return (0);
}
#endif
static int
{
thread_unlock(t);
return (EBUSY);
}
/* drop p_lock while touching the lwp's stack */
thread_unlock(t);
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
return (0);
}
void
{
if (ISWAKEABLE(t) &&
setrun_locked(t);
thread_unlock(t);
}
void
{
p->p_proc_flag |= P_PR_TRACE;
else if (sigisempty(&p->p_sigmask)) {
p->p_proc_flag &= ~P_PR_TRACE;
}
}
static int
{
thread_unlock(t);
return (EBUSY);
/*
* Discard current siginfo_t, if any.
*/
lwp->lwp_cursig = 0;
lwp->lwp_extsig = 0;
if (lwp->lwp_curinfo) {
}
return (0);
}
static int
{
thread_unlock(t);
ttolwp(t)->lwp_curflt = 0;
return (0);
}
static int
{
int error;
*unlocked = 0;
/*
* Can't apply to a system process.
*/
return (EBUSY);
/*
* Verify that the address range does not wrap
* and that only the proper flags were specified.
*/
if ((wflags & ~WA_TRAPAFTER) == 0)
size = 0;
return (EINVAL);
/*
* Don't let the address range go above as->a_userlimit.
* There is no error here, just a limitation.
*/
return (0);
/*
* Compute maximum number of pages this will add.
*/
if ((wflags & ~WA_TRAPAFTER) != 0) {
return (E2BIG);
}
/*
* Force the process to be fully stopped.
*/
if (p == curproc) {
while (holdwatch() != 0)
continue;
continuelwps(p);
*unlocked = 1;
return (error);
}
} else {
pauselwps(p);
while (pr_allstopped(p, 0) > 0) {
/*
* if the process disappears after we
* unmark it and drop p->p_lock.
*/
prunmark(p);
mutex_exit(mp);
/*
* Unpause the process if it exists.
*/
if (p != NULL) {
unpauselwps(p);
}
*unlocked = 1;
return (error);
}
}
}
/*
* Drop p->p_lock in order to perform the rest of this.
* The process is still locked with the P_PR_LOCK flag.
*/
mutex_exit(&p->p_lock);
if (p == curproc) {
setallwatch();
mutex_enter(&p->p_lock);
continuelwps(p);
} else {
mutex_enter(&p->p_lock);
unpauselwps(p);
}
return (error);
}
/* jobcontrol stopped, but with a /proc directed stop in effect */
#define JDSTOPPED(t) \
((t)->t_state == TS_STOPPED && \
(t)->t_whystop == PR_JOBCONTROL && \
((t)->t_proc_flag & TP_PRSTOP))
/*
* pr_agent() creates the agent lwp. If the process is exiting while
* we are creating an agent lwp, then exitlwps() waits until the
* agent has been created using prbarrier().
*/
static int
{
kthread_t *t;
int cid;
int error;
*unlocked = 0;
/*
* Cannot create the /proc agent lwp if :-
* - the process is not fully stopped or directed to stop.
* - there is an agent lwp already.
* - the process has been killed.
* - the process is exiting.
* - it's a vfork(2) parent.
*/
t = prchoose(p); /* returns locked thread */
thread_unlock(t);
return (EBUSY);
}
thread_unlock(t);
mutex_exit(&p->p_lock);
sigfillset(&smask);
mutex_enter(&p->p_lock);
return (ENOMEM);
}
/*
* Because abandoning the agent inside the target process leads to
* a state that is essentially undebuggable, we record the psinfo of
* the process creating the agent and hang that off of the lwp.
*/
/*
* We overload pr_time in the spymaster to denote the time at which the
* agent was created.
*/
mutex_enter(&p->p_lock);
/*
* Someone just changed this thread's scheduling class,
* so try pre-allocating the buffer again. Hopefully we
* don't hit this often.
*/
mutex_exit(&p->p_lock);
goto retry;
}
/*
* Setting t_sysnum to zero causes post_syscall()
* to bypass all syscall checks and go directly to
* if (issig()) psig();
* so that the agent lwp will stop in issig_forreal()
* showing PR_REQUESTED.
*/
/*
* Don't return until the agent is stopped on PR_REQUESTED.
*/
for (;;) {
*unlocked = 1;
/*
* Wait for the agent to stop and notify us.
* If we've been interrupted, return that information.
*/
error = 0;
break;
}
/*
* Confirm that the agent LWP has stopped.
*/
break;
*unlocked = 0;
/*
* Since we dropped the lock on the process, the agent
* may have disappeared or changed. Grab the current
* agent and check fail if it has disappeared.
*/
break;
}
break;
}
}
}
static int
{
int error = 0;
else if (cnt != 0) {
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
/*
* We have no way to return the i/o count,
* like read() or write() would do, so we
* return an error if the i/o was truncated.
*/
}
return (error);
}
static int
{
kthread_t *t;
int error;
return (EINVAL);
if (dogrps) {
int i;
return (EINVAL);
for (i = 0; i < ngrp; i++) {
return (EINVAL);
}
}
if (error)
return (error);
mutex_exit(&p->p_lock);
/* hold old cred so it doesn't disappear while we dup it */
mutex_enter(&p->p_crlock);
mutex_exit(&p->p_crlock);
/* Error checking done above */
if (dogrps) {
}
mutex_enter(&p->p_crlock);
mutex_exit(&p->p_crlock);
/*
* Keep count of processes per uid consistent.
*/
}
/*
* Broadcast the cred change to the threads.
*/
mutex_enter(&p->p_lock);
t = p->p_tlist;
do {
return (0);
}
/*
* Change process credentials to specified zone. Used to temporarily
* set a process to run in the global zone; only transitions between
* the process's actual zone and the global zone are allowed.
*/
static int
{
kthread_t *t;
if (secpolicy_zone_config(cr) != 0)
return (EPERM);
return (EINVAL);
return (EINVAL);
mutex_exit(&p->p_lock);
mutex_enter(&p->p_crlock);
mutex_exit(&p->p_crlock);
mutex_enter(&p->p_crlock);
mutex_exit(&p->p_crlock);
/*
* The target process is changing zones (according to its cred), so
* update the per-zone upcounts, which are based on process creds.
*/
}
/*
* Broadcast the cred change to the threads.
*/
mutex_enter(&p->p_lock);
t = p->p_tlist;
do {
return (0);
}
static int
{
kthread_t *t;
int err;
/*
* Broadcast the cred change to the threads.
*/
t = p->p_tlist;
do {
}
return (err);
}
/*
* Return -1 if the process is the parent of a vfork(1) whose child has yet to
* terminate or perform an exec(2).
*
* Returns 0 if the process is fully stopped except for the current thread (if
* we are operating on our own process), 1 otherwise.
*
* If the watchstop flag is set, then we ignore threads with TP_WATCHSTOP set.
* See holdwatch() for details.
*/
int
{
kthread_t *t;
int rv = 0;
return (-1);
do {
continue;
thread_lock(t);
switch (t->t_state) {
case TS_ZOMB:
case TS_STOPPED:
break;
case TS_SLEEP:
if (!(t->t_flag & T_WAKEABLE) ||
rv = 1;
break;
default:
rv = 1;
break;
}
thread_unlock(t);
}
return (rv);
}
/*
* Cause all lwps in the process to pause (for watchpoint operations).
*/
static void
{
kthread_t *t;
do {
thread_lock(t);
t->t_proc_flag |= TP_PAUSE;
aston(t);
ISWAITING(t)) {
setrun_locked(t);
}
prpokethread(t);
thread_unlock(t);
}
}
/*
* undo the effects of pauselwps()
*/
static void
{
kthread_t *t;
do {
thread_lock(t);
t->t_proc_flag &= ~TP_PAUSE;
if (t->t_state == TS_STOPPED) {
t->t_schedflag |= TS_UNPAUSE;
t->t_dtrace_stop = 0;
setrun_locked(t);
}
thread_unlock(t);
}
}
/*
* Cancel all watched areas. Called from prclose().
*/
proc_t *
{
kthread_t *t;
if (!pr_watch_active(p))
return (p);
/*
* Pause the process before dealing with the watchpoints.
*/
if (p == curproc) {
while (holdwatch() != 0)
continue;
} else {
pauselwps(p);
while (p != NULL && pr_allstopped(p, 0) > 0) {
/*
* if the process disappears after we
* unmark it and drop p->p_lock.
*/
prunmark(p);
mutex_exit(mp);
}
}
if (p == NULL) /* the process disappeared */
return (NULL);
if (pr_watch_active(p)) {
do {
watch_disable(t);
}
}
/*
* If this is the parent of a vfork, the watched page
* list has been moved temporarily to p->p_wpage.
*/
if (avl_numnodes(&p->p_wpage) != 0)
else
mutex_exit(&p->p_lock);
}
}
mutex_enter(&p->p_lock);
}
/*
* Unpause the process now.
*/
if (p == curproc)
continuelwps(p);
else
unpauselwps(p);
return (p);
}