procset.c revision ddc470cc019b5d52e3c2546a8b3104e189611b71
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI" /* from SVr4.0 1.25 */
#include <sys/sysmacros.h>
#include <sys/ucontext.h>
int checkprocset(procset_t *);
/*
* The dotoprocs function locates the process(es) specified
* by the procset structure pointed to by psp. funcp points to a
* function which dotoprocs will call for each process in the
* specified set. The arguments to this function will be a pointer
* to the current process from the set and arg.
* If the called function returns -1, it means that processing of the
* procset should stop and a normal (non-error) return should be made
* to the caller of dotoprocs.
* If the called function returns any other non-zero value the search
* is terminated and the function's return value is returned to
* the caller of dotoprocs. This will normally be an error code.
* Otherwise, dotoprocs will return zero after processing the entire
* process set unless no processes were found in which case ESRCH will
* be returned.
*/
int
{
int error;
int nfound; /* Nbr of processes found. */
/*
* Check that the procset_t is valid.
*/
if (error) {
return (error);
}
/*
* Check for the special value P_MYID in either operand
* and replace it with the correct value. We don't check
* for an error return from getmyid() because the idtypes
* have been validated by the checkprocset() call above.
*/
}
}
/*
* If psp only acts on a single proc, we can reduce pidlock hold time
* by avoiding a needless scan of the entire proc list. Although
* there are many procset_t combinations which might boil down to a
* single proc, the most common case is an AND operation where one
* side is a specific pid, and the other side is P_ALL, so that is
* the case for which we will provide a fast path. Other cases could
* be added in a similar fashion if they were to become significant
* pidlock bottlenecks.
*
* Perform the check symmetrically: either the left or right side may
* specify a pid, with the opposite side being 'all'.
*/
/*
* Specified proc doesn't exist or should
* not be operated on.
* Don't need to make HASZONEACCESS check
* here since prfind() takes care of that.
*/
return (ESRCH);
}
/*
* Operate only on the specified proc. It's okay
* if it's init.
*/
if (error == -1)
error = 0;
return (error);
}
}
nfound = 0;
error = 0;
/*
* If caller is in a non-global zone, skip processes
* in other zones.
*/
continue;
continue;
nfound++;
if (error == -1) {
return (0);
} else if (error) {
return (error);
}
}
}
}
if (nfound == 0) {
return (ESRCH);
}
if (error == -1)
error = 0;
return (error);
}
/*
* Check if a procset_t is valid. Return zero or an errno.
*/
int
{
case P_LWPID:
case P_PID:
case P_PPID:
case P_PGID:
case P_SID:
case P_TASKID:
case P_CID:
case P_UID:
case P_GID:
case P_PROJID:
case P_POOLID:
case P_ZONEID:
case P_CTID:
case P_ALL:
break;
default:
return (EINVAL);
}
case P_LWPID:
case P_PID:
case P_PPID:
case P_PGID:
case P_SID:
case P_TASKID:
case P_CID:
case P_UID:
case P_GID:
case P_PROJID:
case P_POOLID:
case P_ZONEID:
case P_CTID:
case P_ALL:
break;
default:
return (EINVAL);
}
case POP_DIFF:
case POP_AND:
case POP_OR:
case POP_XOR:
break;
default:
return (EINVAL);
}
return (0);
}
/*
* procinset returns 1 if the process pointed to
* by pp is in the process set specified by psp, otherwise 0 is returned.
* The caller should check that the process is not exiting and is not
* in the SYS scheduling class.
*
* This function expects to be called with a valid procset_t.
* The set should be checked using checkprocset() before calling
* this function.
*/
int
{
int loperand = 0;
int roperand = 0;
int lwplinproc = 0;
int lwprinproc = 0;
case P_LWPID:
lwplinproc++;
break;
case P_PID:
loperand++;
break;
case P_PPID:
loperand++;
break;
case P_PGID:
loperand++;
break;
case P_SID:
loperand++;
break;
case P_CID:
/* This case is broken for now. Need to be fixed XXX */
/*
* if (checkcid(psp->p_lid))
*/
loperand++;
break;
case P_TASKID:
loperand++;
break;
case P_UID:
loperand++;
break;
case P_GID:
loperand++;
break;
case P_PROJID:
loperand++;
break;
case P_POOLID:
loperand++;
break;
case P_ZONEID:
loperand++;
break;
case P_CTID:
loperand++;
break;
case P_ALL:
loperand++;
break;
default:
#ifdef DEBUG
return (0);
#else
return (0);
#endif
}
case P_LWPID:
lwprinproc++;
break;
case P_PID:
roperand++;
break;
case P_PPID:
roperand++;
break;
case P_PGID:
roperand++;
break;
case P_SID:
roperand++;
break;
case P_TASKID:
roperand++;
break;
case P_CID:
/* This case is broken for now. Need to be fixed XXX */
/*
* if (checkcid(psp->p_rid))
*/
roperand++;
break;
case P_UID:
roperand++;
break;
case P_GID:
roperand++;
break;
case P_PROJID:
roperand++;
break;
case P_POOLID:
roperand++;
break;
case P_ZONEID:
roperand++;
break;
case P_CTID:
roperand++;
break;
case P_ALL:
roperand++;
break;
default:
#ifdef DEBUG
return (0);
#else
return (0);
#endif
}
case POP_DIFF:
return (1);
else
return (0);
case POP_AND:
return (1);
else
return (0);
case POP_OR:
return (1);
else
return (0);
case POP_XOR:
return (1);
else
return (0);
default:
#ifdef DEBUG
return (0);
#else
return (0);
#endif
}
/* NOTREACHED */
}
/*
* lwpinset returns 1 if the thread pointed to
* by tp is in the process set specified by psp and is not in
* the sys scheduling class - otherwise 0 is returned.
*
* This function expects to be called with a valid procset_t.
* The set should be checked using checkprocset() before calling
* this function.
*/
int
{
int loperand = 0;
int roperand = 0;
int lwplinset = 0;
int lwprinset = 0;
/*
* If process is in the sys class return (0).
*/
return (0);
}
case P_LWPID:
lwplinset ++;
break;
case P_PID:
loperand++;
break;
case P_PPID:
loperand++;
break;
case P_PGID:
loperand++;
break;
case P_SID:
loperand++;
break;
case P_TASKID:
loperand++;
break;
case P_CID:
loperand++;
break;
case P_UID:
loperand++;
break;
case P_GID:
loperand++;
break;
case P_PROJID:
loperand++;
break;
case P_POOLID:
loperand++;
break;
case P_ZONEID:
loperand++;
break;
case P_CTID:
loperand++;
break;
case P_ALL:
loperand++;
break;
default:
#ifdef DEBUG
return (0);
#else
return (0);
#endif
}
case P_LWPID:
lwprinset ++;
break;
case P_PID:
roperand++;
break;
case P_PPID:
roperand++;
break;
case P_PGID:
roperand++;
break;
case P_SID:
roperand++;
break;
case P_TASKID:
roperand++;
break;
case P_CID:
roperand++;
break;
case P_UID:
roperand++;
break;
case P_GID:
roperand++;
break;
case P_PROJID:
roperand++;
break;
case P_POOLID:
roperand++;
break;
case P_ZONEID:
roperand++;
break;
case P_CTID:
roperand++;
break;
case P_ALL:
roperand++;
break;
default:
#ifdef DEBUG
return (0);
#else
return (0);
#endif
}
*done = 1;
case POP_DIFF:
return (1);
else
return (0);
case POP_AND:
return (1);
else
return (0);
case POP_OR:
return (1);
else
return (0);
case POP_XOR:
return (1);
else
return (0);
default:
#ifdef DEBUG
return (0);
#else
return (0);
#endif
}
/* NOTREACHED */
}
/*
* Check for common cases of procsets which specify only the
* current process. cur_inset_only() returns B_TRUE when
* the current process is the only one in the set. B_FALSE
* is returned to indicate that this may not be the case.
*/
{
return (B_TRUE);
return (B_TRUE);
return (B_FALSE);
}
{
switch (idtype) {
case P_LWPID:
case P_PID:
case P_PPID:
case P_PGID:
case P_SID:
return (sid);
case P_TASKID:
case P_CID:
case P_UID:
return (uid);
case P_GID:
return (gid);
case P_PROJID:
case P_POOLID:
case P_ZONEID:
case P_CTID:
case P_ALL:
/*
* The value doesn't matter for P_ALL.
*/
return (0);
default:
return (-1);
}
}
static kthread_t *
{
proc_t *p;
kthread_t *t;
t = curthread;
else {
mutex_enter(&p->p_lock);
mutex_exit(&p->p_lock);
}
return (t);
}
/*
* The dotolwp function locates the LWP(s) specified by the procset structure
* pointed to by psp. If funcp is non-NULL then it points to a function
* which dotolwp will call for each LWP in the specified set.
* LWPIDs specified in the procset structure always refer to lwps in curproc.
* The arguments for this function must be "char *arg", and "kthread_t *tp",
* where tp is a pointer to the current thread from the set.
* Note that these arguments are passed to the function in reversed order
* than the order of arguments passed by dotoprocs() to its callback function.
* Also note that there are two separate cases where this routine returns zero.
* In the first case no mutex is grabbed, in the second the p_lock mutex
* is NOT RELEASED. The priocntl code is expecting this behaviour.
*/
int
{
int error = 0;
int nfound = 0;
int done = 0;
/*
* Check that the procset_t is valid.
*/
if (error) {
return (error);
}
/*
* Check for the special value P_MYID in either operand
* and replace it with the correct value. We don't check
* for an error return from getmyid() because the idtypes
* have been validated by the checkprocset() call above.
*/
}
}
return (0);
}
return (0);
}
do {
nfound ++;
if (error) {
return (error);
}
}
if (nfound == 0) {
return (ESRCH);
}
return (error);
}