xref: /titanic_53/usr/src/uts/common/os/pid.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/proc.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/tuneable.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/var.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/prsystm.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/session.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/bitmap.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
49*7c478bd9Sstevel@tonic-gate #include <c2/audit.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/zone.h>
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate /* directory entries for /proc */
53*7c478bd9Sstevel@tonic-gate union procent {
54*7c478bd9Sstevel@tonic-gate 	proc_t *pe_proc;
55*7c478bd9Sstevel@tonic-gate 	union procent *pe_next;
56*7c478bd9Sstevel@tonic-gate };
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate struct pid pid0 = {
59*7c478bd9Sstevel@tonic-gate 	0,		/* pid_prinactive */
60*7c478bd9Sstevel@tonic-gate 	1,		/* pid_pgorphaned */
61*7c478bd9Sstevel@tonic-gate 	0,		/* pid_padding	*/
62*7c478bd9Sstevel@tonic-gate 	0,		/* pid_prslot	*/
63*7c478bd9Sstevel@tonic-gate 	0,		/* pid_id	*/
64*7c478bd9Sstevel@tonic-gate 	NULL,		/* pid_pglink	*/
65*7c478bd9Sstevel@tonic-gate 	NULL,		/* pid_link	*/
66*7c478bd9Sstevel@tonic-gate 	3		/* pid_ref	*/
67*7c478bd9Sstevel@tonic-gate };
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate static int pid_hashlen = 4;	/* desired average hash chain length */
70*7c478bd9Sstevel@tonic-gate static int pid_hashsz;		/* number of buckets in the hash table */
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate #define	HASHPID(pid)	(pidhash[((pid)&(pid_hashsz-1))])
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate extern uint_t nproc;
75*7c478bd9Sstevel@tonic-gate extern struct kmem_cache *process_cache;
76*7c478bd9Sstevel@tonic-gate static void	upcount_init(void);
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate kmutex_t	pidlock;	/* global process lock */
79*7c478bd9Sstevel@tonic-gate kmutex_t	pr_pidlock;	/* /proc global process lock */
80*7c478bd9Sstevel@tonic-gate kcondvar_t	*pr_pid_cv;	/* for /proc, one per process slot */
81*7c478bd9Sstevel@tonic-gate struct plock	*proc_lock;	/* persistent array of p_lock's */
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate /*
84*7c478bd9Sstevel@tonic-gate  * See the comment above pid_getlockslot() for a detailed explanation of this
85*7c478bd9Sstevel@tonic-gate  * constant.  Note that a PLOCK_SHIFT of 3 implies 64-byte coherence
86*7c478bd9Sstevel@tonic-gate  * granularity; if the coherence granularity is ever changed, this constant
87*7c478bd9Sstevel@tonic-gate  * should be modified to reflect the change to minimize proc_lock false
88*7c478bd9Sstevel@tonic-gate  * sharing (correctness, however, is guaranteed regardless of the coherence
89*7c478bd9Sstevel@tonic-gate  * granularity).
90*7c478bd9Sstevel@tonic-gate  */
91*7c478bd9Sstevel@tonic-gate #define	PLOCK_SHIFT	3
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate static kmutex_t	pidlinklock;
94*7c478bd9Sstevel@tonic-gate static struct pid **pidhash;
95*7c478bd9Sstevel@tonic-gate static pid_t minpid;
96*7c478bd9Sstevel@tonic-gate static pid_t mpid;
97*7c478bd9Sstevel@tonic-gate static union procent *procdir;
98*7c478bd9Sstevel@tonic-gate static union procent *procentfree;
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate static struct pid *
101*7c478bd9Sstevel@tonic-gate pid_lookup(pid_t pid)
102*7c478bd9Sstevel@tonic-gate {
103*7c478bd9Sstevel@tonic-gate 	struct pid *pidp;
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlinklock));
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	for (pidp = HASHPID(pid); pidp; pidp = pidp->pid_link) {
108*7c478bd9Sstevel@tonic-gate 		if (pidp->pid_id == pid) {
109*7c478bd9Sstevel@tonic-gate 			ASSERT(pidp->pid_ref > 0);
110*7c478bd9Sstevel@tonic-gate 			break;
111*7c478bd9Sstevel@tonic-gate 		}
112*7c478bd9Sstevel@tonic-gate 	}
113*7c478bd9Sstevel@tonic-gate 	return (pidp);
114*7c478bd9Sstevel@tonic-gate }
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate void
117*7c478bd9Sstevel@tonic-gate pid_setmin(void)
118*7c478bd9Sstevel@tonic-gate {
119*7c478bd9Sstevel@tonic-gate 	if (jump_pid && jump_pid > mpid)
120*7c478bd9Sstevel@tonic-gate 		minpid = mpid = jump_pid;
121*7c478bd9Sstevel@tonic-gate 	else
122*7c478bd9Sstevel@tonic-gate 		minpid = mpid + 1;
123*7c478bd9Sstevel@tonic-gate }
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate /*
126*7c478bd9Sstevel@tonic-gate  * When prslots are simply used as an index to determine a process' p_lock,
127*7c478bd9Sstevel@tonic-gate  * adjacent prslots share adjacent p_locks.  On machines where the size
128*7c478bd9Sstevel@tonic-gate  * of a mutex is smaller than that of a cache line (which, as of this writing,
129*7c478bd9Sstevel@tonic-gate  * is true for all machines on which Solaris runs), this can potentially
130*7c478bd9Sstevel@tonic-gate  * induce false sharing.  The standard solution for false sharing is to pad
131*7c478bd9Sstevel@tonic-gate  * out one's data structures (in this case, struct plock).  However,
132*7c478bd9Sstevel@tonic-gate  * given the size and (generally) sparse use of the proc_lock array, this
133*7c478bd9Sstevel@tonic-gate  * is suboptimal.  We therefore stride through the proc_lock array with
134*7c478bd9Sstevel@tonic-gate  * a stride of PLOCK_SHIFT.  PLOCK_SHIFT should be defined as:
135*7c478bd9Sstevel@tonic-gate  *
136*7c478bd9Sstevel@tonic-gate  *   log_2 (coherence_granularity / sizeof (kmutex_t))
137*7c478bd9Sstevel@tonic-gate  *
138*7c478bd9Sstevel@tonic-gate  * Under this scheme, false sharing is still possible -- but only when
139*7c478bd9Sstevel@tonic-gate  * the number of active processes is very large.  Note that the one-to-one
140*7c478bd9Sstevel@tonic-gate  * mapping between prslots and lockslots is maintained.
141*7c478bd9Sstevel@tonic-gate  */
142*7c478bd9Sstevel@tonic-gate static int
143*7c478bd9Sstevel@tonic-gate pid_getlockslot(int prslot)
144*7c478bd9Sstevel@tonic-gate {
145*7c478bd9Sstevel@tonic-gate 	int even = (v.v_proc >> PLOCK_SHIFT) << PLOCK_SHIFT;
146*7c478bd9Sstevel@tonic-gate 	int perlap = even >> PLOCK_SHIFT;
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 	if (prslot >= even)
149*7c478bd9Sstevel@tonic-gate 		return (prslot);
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 	return (((prslot % perlap) << PLOCK_SHIFT) + (prslot / perlap));
152*7c478bd9Sstevel@tonic-gate }
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate /*
155*7c478bd9Sstevel@tonic-gate  * This function assigns a pid for use in a fork request.  It allocates
156*7c478bd9Sstevel@tonic-gate  * a pid structure, tries to find an empty slot in the proc table,
157*7c478bd9Sstevel@tonic-gate  * and selects the process id.
158*7c478bd9Sstevel@tonic-gate  *
159*7c478bd9Sstevel@tonic-gate  * pid_assign() returns the new pid on success, -1 on failure.
160*7c478bd9Sstevel@tonic-gate  */
161*7c478bd9Sstevel@tonic-gate pid_t
162*7c478bd9Sstevel@tonic-gate pid_assign(proc_t *prp)
163*7c478bd9Sstevel@tonic-gate {
164*7c478bd9Sstevel@tonic-gate 	struct pid *pidp;
165*7c478bd9Sstevel@tonic-gate 	union procent *pep;
166*7c478bd9Sstevel@tonic-gate 	pid_t newpid, startpid;
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 	pidp = kmem_zalloc(sizeof (struct pid), KM_SLEEP);
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlinklock);
171*7c478bd9Sstevel@tonic-gate 	if ((pep = procentfree) == NULL) {
172*7c478bd9Sstevel@tonic-gate 		/*
173*7c478bd9Sstevel@tonic-gate 		 * ran out of /proc directory entries
174*7c478bd9Sstevel@tonic-gate 		 */
175*7c478bd9Sstevel@tonic-gate 		goto failed;
176*7c478bd9Sstevel@tonic-gate 	}
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 	/*
179*7c478bd9Sstevel@tonic-gate 	 * Allocate a pid
180*7c478bd9Sstevel@tonic-gate 	 */
181*7c478bd9Sstevel@tonic-gate 	startpid = mpid;
182*7c478bd9Sstevel@tonic-gate 	do  {
183*7c478bd9Sstevel@tonic-gate 		newpid = (++mpid == maxpid ? mpid = minpid : mpid);
184*7c478bd9Sstevel@tonic-gate 	} while (pid_lookup(newpid) && newpid != startpid);
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	if (newpid == startpid && pid_lookup(newpid)) {
187*7c478bd9Sstevel@tonic-gate 		/* couldn't find a free pid */
188*7c478bd9Sstevel@tonic-gate 		goto failed;
189*7c478bd9Sstevel@tonic-gate 	}
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate 	procentfree = pep->pe_next;
192*7c478bd9Sstevel@tonic-gate 	pep->pe_proc = prp;
193*7c478bd9Sstevel@tonic-gate 	prp->p_pidp = pidp;
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	/*
196*7c478bd9Sstevel@tonic-gate 	 * Put pid into the pid hash table.
197*7c478bd9Sstevel@tonic-gate 	 */
198*7c478bd9Sstevel@tonic-gate 	pidp->pid_link = HASHPID(newpid);
199*7c478bd9Sstevel@tonic-gate 	HASHPID(newpid) = pidp;
200*7c478bd9Sstevel@tonic-gate 	pidp->pid_ref = 1;
201*7c478bd9Sstevel@tonic-gate 	pidp->pid_id = newpid;
202*7c478bd9Sstevel@tonic-gate 	pidp->pid_prslot = pep - procdir;
203*7c478bd9Sstevel@tonic-gate 	prp->p_lockp = &proc_lock[pid_getlockslot(pidp->pid_prslot)];
204*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlinklock);
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	return (newpid);
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate failed:
209*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlinklock);
210*7c478bd9Sstevel@tonic-gate 	kmem_free(pidp, sizeof (struct pid));
211*7c478bd9Sstevel@tonic-gate 	return (-1);
212*7c478bd9Sstevel@tonic-gate }
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate /*
215*7c478bd9Sstevel@tonic-gate  * decrement the reference count for pid
216*7c478bd9Sstevel@tonic-gate  */
217*7c478bd9Sstevel@tonic-gate int
218*7c478bd9Sstevel@tonic-gate pid_rele(struct pid *pidp)
219*7c478bd9Sstevel@tonic-gate {
220*7c478bd9Sstevel@tonic-gate 	struct pid **pidpp;
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlinklock);
223*7c478bd9Sstevel@tonic-gate 	ASSERT(pidp != &pid0);
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	pidpp = &HASHPID(pidp->pid_id);
226*7c478bd9Sstevel@tonic-gate 	for (;;) {
227*7c478bd9Sstevel@tonic-gate 		ASSERT(*pidpp != NULL);
228*7c478bd9Sstevel@tonic-gate 		if (*pidpp == pidp)
229*7c478bd9Sstevel@tonic-gate 			break;
230*7c478bd9Sstevel@tonic-gate 		pidpp = &(*pidpp)->pid_link;
231*7c478bd9Sstevel@tonic-gate 	}
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	*pidpp = pidp->pid_link;
234*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlinklock);
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	kmem_free(pidp, sizeof (*pidp));
237*7c478bd9Sstevel@tonic-gate 	return (0);
238*7c478bd9Sstevel@tonic-gate }
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate void
241*7c478bd9Sstevel@tonic-gate proc_entry_free(struct pid *pidp)
242*7c478bd9Sstevel@tonic-gate {
243*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlinklock);
244*7c478bd9Sstevel@tonic-gate 	pidp->pid_prinactive = 1;
245*7c478bd9Sstevel@tonic-gate 	procdir[pidp->pid_prslot].pe_next = procentfree;
246*7c478bd9Sstevel@tonic-gate 	procentfree = &procdir[pidp->pid_prslot];
247*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlinklock);
248*7c478bd9Sstevel@tonic-gate }
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate void
251*7c478bd9Sstevel@tonic-gate pid_exit(proc_t *prp)
252*7c478bd9Sstevel@tonic-gate {
253*7c478bd9Sstevel@tonic-gate 	struct pid *pidp;
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	/*
258*7c478bd9Sstevel@tonic-gate 	 * Exit process group.  If it is NULL, it's because fork failed
259*7c478bd9Sstevel@tonic-gate 	 * before calling pgjoin().
260*7c478bd9Sstevel@tonic-gate 	 */
261*7c478bd9Sstevel@tonic-gate 	ASSERT(prp->p_pgidp != NULL || prp->p_stat == SIDL);
262*7c478bd9Sstevel@tonic-gate 	if (prp->p_pgidp != NULL)
263*7c478bd9Sstevel@tonic-gate 		pgexit(prp);
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 	SESS_RELE(prp->p_sessp);
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	pidp = prp->p_pidp;
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 	proc_entry_free(pidp);
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT
272*7c478bd9Sstevel@tonic-gate 	if (audit_active)
273*7c478bd9Sstevel@tonic-gate 		audit_pfree(prp);
274*7c478bd9Sstevel@tonic-gate #endif
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 	if (practive == prp) {
277*7c478bd9Sstevel@tonic-gate 		practive = prp->p_next;
278*7c478bd9Sstevel@tonic-gate 	}
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	if (prp->p_next) {
281*7c478bd9Sstevel@tonic-gate 		prp->p_next->p_prev = prp->p_prev;
282*7c478bd9Sstevel@tonic-gate 	}
283*7c478bd9Sstevel@tonic-gate 	if (prp->p_prev) {
284*7c478bd9Sstevel@tonic-gate 		prp->p_prev->p_next = prp->p_next;
285*7c478bd9Sstevel@tonic-gate 	}
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	PID_RELE(pidp);
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&prp->p_crlock);
290*7c478bd9Sstevel@tonic-gate 	kmem_cache_free(process_cache, prp);
291*7c478bd9Sstevel@tonic-gate 	nproc--;
292*7c478bd9Sstevel@tonic-gate }
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate /*
295*7c478bd9Sstevel@tonic-gate  * Find a process visible from the specified zone given its process ID.
296*7c478bd9Sstevel@tonic-gate  */
297*7c478bd9Sstevel@tonic-gate proc_t *
298*7c478bd9Sstevel@tonic-gate prfind_zone(pid_t pid, zoneid_t zoneid)
299*7c478bd9Sstevel@tonic-gate {
300*7c478bd9Sstevel@tonic-gate 	struct pid *pidp;
301*7c478bd9Sstevel@tonic-gate 	proc_t *p;
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlinklock);
306*7c478bd9Sstevel@tonic-gate 	pidp = pid_lookup(pid);
307*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlinklock);
308*7c478bd9Sstevel@tonic-gate 	if (pidp != NULL && pidp->pid_prinactive == 0) {
309*7c478bd9Sstevel@tonic-gate 		p = procdir[pidp->pid_prslot].pe_proc;
310*7c478bd9Sstevel@tonic-gate 		if (zoneid == ALL_ZONES || p->p_zone->zone_id == zoneid)
311*7c478bd9Sstevel@tonic-gate 			return (p);
312*7c478bd9Sstevel@tonic-gate 	}
313*7c478bd9Sstevel@tonic-gate 	return (NULL);
314*7c478bd9Sstevel@tonic-gate }
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate /*
317*7c478bd9Sstevel@tonic-gate  * Find a process given its process ID.  This obeys zone restrictions,
318*7c478bd9Sstevel@tonic-gate  * so if the caller is in a non-global zone it won't find processes
319*7c478bd9Sstevel@tonic-gate  * associated with other zones.  Use prfind_zone(pid, ALL_ZONES) to
320*7c478bd9Sstevel@tonic-gate  * bypass this restriction.
321*7c478bd9Sstevel@tonic-gate  */
322*7c478bd9Sstevel@tonic-gate proc_t *
323*7c478bd9Sstevel@tonic-gate prfind(pid_t pid)
324*7c478bd9Sstevel@tonic-gate {
325*7c478bd9Sstevel@tonic-gate 	zoneid_t zoneid;
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	if (INGLOBALZONE(curproc))
328*7c478bd9Sstevel@tonic-gate 		zoneid = ALL_ZONES;
329*7c478bd9Sstevel@tonic-gate 	else
330*7c478bd9Sstevel@tonic-gate 		zoneid = getzoneid();
331*7c478bd9Sstevel@tonic-gate 	return (prfind_zone(pid, zoneid));
332*7c478bd9Sstevel@tonic-gate }
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate proc_t *
335*7c478bd9Sstevel@tonic-gate pgfind_zone(pid_t pgid, zoneid_t zoneid)
336*7c478bd9Sstevel@tonic-gate {
337*7c478bd9Sstevel@tonic-gate 	struct pid *pidp;
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlinklock);
342*7c478bd9Sstevel@tonic-gate 	pidp = pid_lookup(pgid);
343*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlinklock);
344*7c478bd9Sstevel@tonic-gate 	if (pidp != NULL) {
345*7c478bd9Sstevel@tonic-gate 		proc_t *p = pidp->pid_pglink;
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 		if (zoneid == ALL_ZONES || pgid == 0 || p == NULL ||
348*7c478bd9Sstevel@tonic-gate 		    p->p_zone->zone_id == zoneid)
349*7c478bd9Sstevel@tonic-gate 			return (p);
350*7c478bd9Sstevel@tonic-gate 	}
351*7c478bd9Sstevel@tonic-gate 	return (NULL);
352*7c478bd9Sstevel@tonic-gate }
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate /*
355*7c478bd9Sstevel@tonic-gate  * return the head of the list of processes whose process group ID is 'pgid',
356*7c478bd9Sstevel@tonic-gate  * or NULL, if no such process group
357*7c478bd9Sstevel@tonic-gate  */
358*7c478bd9Sstevel@tonic-gate proc_t *
359*7c478bd9Sstevel@tonic-gate pgfind(pid_t pgid)
360*7c478bd9Sstevel@tonic-gate {
361*7c478bd9Sstevel@tonic-gate 	zoneid_t zoneid;
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 	if (INGLOBALZONE(curproc))
364*7c478bd9Sstevel@tonic-gate 		zoneid = ALL_ZONES;
365*7c478bd9Sstevel@tonic-gate 	else
366*7c478bd9Sstevel@tonic-gate 		zoneid = getzoneid();
367*7c478bd9Sstevel@tonic-gate 	return (pgfind_zone(pgid, zoneid));
368*7c478bd9Sstevel@tonic-gate }
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate /*
371*7c478bd9Sstevel@tonic-gate  * If pid exists, find its proc, acquire its p_lock and mark it P_PR_LOCK.
372*7c478bd9Sstevel@tonic-gate  * Returns the proc pointer on success, NULL on failure.  sprlock() is
373*7c478bd9Sstevel@tonic-gate  * really just a stripped-down version of pr_p_lock() to allow practive
374*7c478bd9Sstevel@tonic-gate  * walkers like dofusers() and dumpsys() to synchronize with /proc.
375*7c478bd9Sstevel@tonic-gate  */
376*7c478bd9Sstevel@tonic-gate proc_t *
377*7c478bd9Sstevel@tonic-gate sprlock_zone(pid_t pid, zoneid_t zoneid)
378*7c478bd9Sstevel@tonic-gate {
379*7c478bd9Sstevel@tonic-gate 	proc_t *p;
380*7c478bd9Sstevel@tonic-gate 	kmutex_t *mp;
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 	for (;;) {
383*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
384*7c478bd9Sstevel@tonic-gate 		if ((p = prfind_zone(pid, zoneid)) == NULL) {
385*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
386*7c478bd9Sstevel@tonic-gate 			return (NULL);
387*7c478bd9Sstevel@tonic-gate 		}
388*7c478bd9Sstevel@tonic-gate 		/*
389*7c478bd9Sstevel@tonic-gate 		 * p_lock is persistent, but p itself is not -- it could
390*7c478bd9Sstevel@tonic-gate 		 * vanish during cv_wait().  Load p->p_lock now so we can
391*7c478bd9Sstevel@tonic-gate 		 * drop it after cv_wait() without referencing p.
392*7c478bd9Sstevel@tonic-gate 		 */
393*7c478bd9Sstevel@tonic-gate 		mp = &p->p_lock;
394*7c478bd9Sstevel@tonic-gate 		mutex_enter(mp);
395*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
396*7c478bd9Sstevel@tonic-gate 		/*
397*7c478bd9Sstevel@tonic-gate 		 * If the process is in some half-baked state, fail.
398*7c478bd9Sstevel@tonic-gate 		 */
399*7c478bd9Sstevel@tonic-gate 		if (p->p_stat == SZOMB || p->p_stat == SIDL ||
400*7c478bd9Sstevel@tonic-gate 		    p->p_tlist == NULL || (p->p_flag & SEXITLWPS)) {
401*7c478bd9Sstevel@tonic-gate 			mutex_exit(mp);
402*7c478bd9Sstevel@tonic-gate 			return (NULL);
403*7c478bd9Sstevel@tonic-gate 		}
404*7c478bd9Sstevel@tonic-gate 		if (panicstr)
405*7c478bd9Sstevel@tonic-gate 			return (p);
406*7c478bd9Sstevel@tonic-gate 		if (!(p->p_proc_flag & P_PR_LOCK))
407*7c478bd9Sstevel@tonic-gate 			break;
408*7c478bd9Sstevel@tonic-gate 		cv_wait(&pr_pid_cv[p->p_slot], mp);
409*7c478bd9Sstevel@tonic-gate 		mutex_exit(mp);
410*7c478bd9Sstevel@tonic-gate 	}
411*7c478bd9Sstevel@tonic-gate 	p->p_proc_flag |= P_PR_LOCK;
412*7c478bd9Sstevel@tonic-gate 	THREAD_KPRI_REQUEST();
413*7c478bd9Sstevel@tonic-gate 	return (p);
414*7c478bd9Sstevel@tonic-gate }
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate proc_t *
417*7c478bd9Sstevel@tonic-gate sprlock(pid_t pid)
418*7c478bd9Sstevel@tonic-gate {
419*7c478bd9Sstevel@tonic-gate 	zoneid_t zoneid;
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 	if (INGLOBALZONE(curproc))
422*7c478bd9Sstevel@tonic-gate 		zoneid = ALL_ZONES;
423*7c478bd9Sstevel@tonic-gate 	else
424*7c478bd9Sstevel@tonic-gate 		zoneid = getzoneid();
425*7c478bd9Sstevel@tonic-gate 	return (sprlock_zone(pid, zoneid));
426*7c478bd9Sstevel@tonic-gate }
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate void
429*7c478bd9Sstevel@tonic-gate sprlock_proc(proc_t *p)
430*7c478bd9Sstevel@tonic-gate {
431*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	while (p->p_proc_flag & P_PR_LOCK) {
434*7c478bd9Sstevel@tonic-gate 		cv_wait(&pr_pid_cv[p->p_slot], &p->p_lock);
435*7c478bd9Sstevel@tonic-gate 	}
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 	p->p_proc_flag |= P_PR_LOCK;
438*7c478bd9Sstevel@tonic-gate 	THREAD_KPRI_REQUEST();
439*7c478bd9Sstevel@tonic-gate }
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate void
442*7c478bd9Sstevel@tonic-gate sprunlock(proc_t *p)
443*7c478bd9Sstevel@tonic-gate {
444*7c478bd9Sstevel@tonic-gate 	if (panicstr) {
445*7c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
446*7c478bd9Sstevel@tonic-gate 		return;
447*7c478bd9Sstevel@tonic-gate 	}
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	ASSERT(p->p_proc_flag & P_PR_LOCK);
450*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&p->p_lock));
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 	cv_signal(&pr_pid_cv[p->p_slot]);
453*7c478bd9Sstevel@tonic-gate 	p->p_proc_flag &= ~P_PR_LOCK;
454*7c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
455*7c478bd9Sstevel@tonic-gate 	THREAD_KPRI_RELEASE();
456*7c478bd9Sstevel@tonic-gate }
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate void
459*7c478bd9Sstevel@tonic-gate pid_init(void)
460*7c478bd9Sstevel@tonic-gate {
461*7c478bd9Sstevel@tonic-gate 	int i;
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	pid_hashsz = 1 << highbit(v.v_proc / pid_hashlen);
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	pidhash = kmem_zalloc(sizeof (struct pid *) * pid_hashsz, KM_SLEEP);
466*7c478bd9Sstevel@tonic-gate 	procdir = kmem_alloc(sizeof (union procent) * v.v_proc, KM_SLEEP);
467*7c478bd9Sstevel@tonic-gate 	pr_pid_cv = kmem_zalloc(sizeof (kcondvar_t) * v.v_proc, KM_SLEEP);
468*7c478bd9Sstevel@tonic-gate 	proc_lock = kmem_zalloc(sizeof (struct plock) * v.v_proc, KM_SLEEP);
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	nproc = 1;
471*7c478bd9Sstevel@tonic-gate 	practive = proc_sched;
472*7c478bd9Sstevel@tonic-gate 	proc_sched->p_next = NULL;
473*7c478bd9Sstevel@tonic-gate 	procdir[0].pe_proc = proc_sched;
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	procentfree = &procdir[1];
476*7c478bd9Sstevel@tonic-gate 	for (i = 1; i < v.v_proc - 1; i++)
477*7c478bd9Sstevel@tonic-gate 		procdir[i].pe_next = &procdir[i+1];
478*7c478bd9Sstevel@tonic-gate 	procdir[i].pe_next = NULL;
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	HASHPID(0) = &pid0;
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	upcount_init();
483*7c478bd9Sstevel@tonic-gate }
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate proc_t *
486*7c478bd9Sstevel@tonic-gate pid_entry(int slot)
487*7c478bd9Sstevel@tonic-gate {
488*7c478bd9Sstevel@tonic-gate 	union procent *pep;
489*7c478bd9Sstevel@tonic-gate 	proc_t *prp;
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
492*7c478bd9Sstevel@tonic-gate 	ASSERT(slot >= 0 && slot < v.v_proc);
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 	pep = procdir[slot].pe_next;
495*7c478bd9Sstevel@tonic-gate 	if (pep >= procdir && pep < &procdir[v.v_proc])
496*7c478bd9Sstevel@tonic-gate 		return (NULL);
497*7c478bd9Sstevel@tonic-gate 	prp = procdir[slot].pe_proc;
498*7c478bd9Sstevel@tonic-gate 	if (prp != 0 && prp->p_stat == SIDL)
499*7c478bd9Sstevel@tonic-gate 		return (NULL);
500*7c478bd9Sstevel@tonic-gate 	return (prp);
501*7c478bd9Sstevel@tonic-gate }
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate /*
504*7c478bd9Sstevel@tonic-gate  * Send the specified signal to all processes whose process group ID is
505*7c478bd9Sstevel@tonic-gate  * equal to 'pgid'
506*7c478bd9Sstevel@tonic-gate  */
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate void
509*7c478bd9Sstevel@tonic-gate signal(pid_t pgid, int sig)
510*7c478bd9Sstevel@tonic-gate {
511*7c478bd9Sstevel@tonic-gate 	struct pid *pidp;
512*7c478bd9Sstevel@tonic-gate 	proc_t *prp;
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlock);
515*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlinklock);
516*7c478bd9Sstevel@tonic-gate 	if (pgid == 0 || (pidp = pid_lookup(pgid)) == NULL) {
517*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlinklock);
518*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
519*7c478bd9Sstevel@tonic-gate 		return;
520*7c478bd9Sstevel@tonic-gate 	}
521*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlinklock);
522*7c478bd9Sstevel@tonic-gate 	for (prp = pidp->pid_pglink; prp; prp = prp->p_pglink) {
523*7c478bd9Sstevel@tonic-gate 		mutex_enter(&prp->p_lock);
524*7c478bd9Sstevel@tonic-gate 		sigtoproc(prp, NULL, sig);
525*7c478bd9Sstevel@tonic-gate 		mutex_exit(&prp->p_lock);
526*7c478bd9Sstevel@tonic-gate 	}
527*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlock);
528*7c478bd9Sstevel@tonic-gate }
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate /*
531*7c478bd9Sstevel@tonic-gate  * Send the specified signal to the specified process
532*7c478bd9Sstevel@tonic-gate  */
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate void
535*7c478bd9Sstevel@tonic-gate prsignal(struct pid *pidp, int sig)
536*7c478bd9Sstevel@tonic-gate {
537*7c478bd9Sstevel@tonic-gate 	if (!(pidp->pid_prinactive))
538*7c478bd9Sstevel@tonic-gate 		psignal(procdir[pidp->pid_prslot].pe_proc, sig);
539*7c478bd9Sstevel@tonic-gate }
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate /*
544*7c478bd9Sstevel@tonic-gate  * DDI/DKI interfaces for drivers to send signals to processes
545*7c478bd9Sstevel@tonic-gate  */
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate /*
548*7c478bd9Sstevel@tonic-gate  * obtain an opaque reference to a process for signaling
549*7c478bd9Sstevel@tonic-gate  */
550*7c478bd9Sstevel@tonic-gate void *
551*7c478bd9Sstevel@tonic-gate proc_ref(void)
552*7c478bd9Sstevel@tonic-gate {
553*7c478bd9Sstevel@tonic-gate 	struct pid *pidp;
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlock);
556*7c478bd9Sstevel@tonic-gate 	pidp = curproc->p_pidp;
557*7c478bd9Sstevel@tonic-gate 	PID_HOLD(pidp);
558*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlock);
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 	return (pidp);
561*7c478bd9Sstevel@tonic-gate }
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate /*
564*7c478bd9Sstevel@tonic-gate  * release a reference to a process
565*7c478bd9Sstevel@tonic-gate  * - a process can exit even if a driver has a reference to it
566*7c478bd9Sstevel@tonic-gate  * - one proc_unref for every proc_ref
567*7c478bd9Sstevel@tonic-gate  */
568*7c478bd9Sstevel@tonic-gate void
569*7c478bd9Sstevel@tonic-gate proc_unref(void *pref)
570*7c478bd9Sstevel@tonic-gate {
571*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlock);
572*7c478bd9Sstevel@tonic-gate 	PID_RELE((struct pid *)pref);
573*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlock);
574*7c478bd9Sstevel@tonic-gate }
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate /*
577*7c478bd9Sstevel@tonic-gate  * send a signal to a process
578*7c478bd9Sstevel@tonic-gate  *
579*7c478bd9Sstevel@tonic-gate  * - send the process the signal
580*7c478bd9Sstevel@tonic-gate  * - if the process went away, return a -1
581*7c478bd9Sstevel@tonic-gate  * - if the process is still there return 0
582*7c478bd9Sstevel@tonic-gate  */
583*7c478bd9Sstevel@tonic-gate int
584*7c478bd9Sstevel@tonic-gate proc_signal(void *pref, int sig)
585*7c478bd9Sstevel@tonic-gate {
586*7c478bd9Sstevel@tonic-gate 	struct pid *pidp = pref;
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 	prsignal(pidp, sig);
589*7c478bd9Sstevel@tonic-gate 	return (pidp->pid_prinactive ? -1 : 0);
590*7c478bd9Sstevel@tonic-gate }
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate static struct upcount	**upc_hash;	/* a boot time allocated array */
594*7c478bd9Sstevel@tonic-gate static ulong_t		upc_hashmask;
595*7c478bd9Sstevel@tonic-gate #define	UPC_HASH(x, y)	((ulong_t)(x ^ y) & upc_hashmask)
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate /*
598*7c478bd9Sstevel@tonic-gate  * Get us off the ground.  Called once at boot.
599*7c478bd9Sstevel@tonic-gate  */
600*7c478bd9Sstevel@tonic-gate void
601*7c478bd9Sstevel@tonic-gate upcount_init(void)
602*7c478bd9Sstevel@tonic-gate {
603*7c478bd9Sstevel@tonic-gate 	ulong_t	upc_hashsize;
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 	/*
606*7c478bd9Sstevel@tonic-gate 	 * An entry per MB of memory is our current guess
607*7c478bd9Sstevel@tonic-gate 	 */
608*7c478bd9Sstevel@tonic-gate 	/*
609*7c478bd9Sstevel@tonic-gate 	 * 2^20 is a meg, so shifting right by 20 - PAGESHIFT
610*7c478bd9Sstevel@tonic-gate 	 * converts pages to megs (without overflowing a u_int
611*7c478bd9Sstevel@tonic-gate 	 * if you have more than 4G of memory, like ptob(physmem)/1M
612*7c478bd9Sstevel@tonic-gate 	 * would).
613*7c478bd9Sstevel@tonic-gate 	 */
614*7c478bd9Sstevel@tonic-gate 	upc_hashsize = (1 << highbit(physmem >> (20 - PAGESHIFT)));
615*7c478bd9Sstevel@tonic-gate 	upc_hashmask = upc_hashsize - 1;
616*7c478bd9Sstevel@tonic-gate 	upc_hash = kmem_zalloc(upc_hashsize * sizeof (struct upcount *),
617*7c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
618*7c478bd9Sstevel@tonic-gate }
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate /*
621*7c478bd9Sstevel@tonic-gate  * Increment the number of processes associated with a given uid and zoneid.
622*7c478bd9Sstevel@tonic-gate  */
623*7c478bd9Sstevel@tonic-gate void
624*7c478bd9Sstevel@tonic-gate upcount_inc(uid_t uid, zoneid_t zoneid)
625*7c478bd9Sstevel@tonic-gate {
626*7c478bd9Sstevel@tonic-gate 	struct upcount	**upc, **hupc;
627*7c478bd9Sstevel@tonic-gate 	struct upcount	*new;
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
630*7c478bd9Sstevel@tonic-gate 	new = NULL;
631*7c478bd9Sstevel@tonic-gate 	hupc = &upc_hash[UPC_HASH(uid, zoneid)];
632*7c478bd9Sstevel@tonic-gate top:
633*7c478bd9Sstevel@tonic-gate 	upc = hupc;
634*7c478bd9Sstevel@tonic-gate 	while ((*upc) != NULL) {
635*7c478bd9Sstevel@tonic-gate 		if ((*upc)->up_uid == uid && (*upc)->up_zoneid == zoneid) {
636*7c478bd9Sstevel@tonic-gate 			(*upc)->up_count++;
637*7c478bd9Sstevel@tonic-gate 			if (new) {
638*7c478bd9Sstevel@tonic-gate 				/*
639*7c478bd9Sstevel@tonic-gate 				 * did not need `new' afterall.
640*7c478bd9Sstevel@tonic-gate 				 */
641*7c478bd9Sstevel@tonic-gate 				kmem_free(new, sizeof (*new));
642*7c478bd9Sstevel@tonic-gate 			}
643*7c478bd9Sstevel@tonic-gate 			return;
644*7c478bd9Sstevel@tonic-gate 		}
645*7c478bd9Sstevel@tonic-gate 		upc = &(*upc)->up_next;
646*7c478bd9Sstevel@tonic-gate 	}
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate 	/*
649*7c478bd9Sstevel@tonic-gate 	 * There is no entry for this <uid,zoneid> pair.
650*7c478bd9Sstevel@tonic-gate 	 * Allocate one.  If we have to drop pidlock, check
651*7c478bd9Sstevel@tonic-gate 	 * again.
652*7c478bd9Sstevel@tonic-gate 	 */
653*7c478bd9Sstevel@tonic-gate 	if (new == NULL) {
654*7c478bd9Sstevel@tonic-gate 		new = (struct upcount *)kmem_alloc(sizeof (*new), KM_NOSLEEP);
655*7c478bd9Sstevel@tonic-gate 		if (new == NULL) {
656*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
657*7c478bd9Sstevel@tonic-gate 			new = (struct upcount *)kmem_alloc(sizeof (*new),
658*7c478bd9Sstevel@tonic-gate 			    KM_SLEEP);
659*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pidlock);
660*7c478bd9Sstevel@tonic-gate 			goto top;
661*7c478bd9Sstevel@tonic-gate 		}
662*7c478bd9Sstevel@tonic-gate 	}
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	/*
666*7c478bd9Sstevel@tonic-gate 	 * On the assumption that a new user is going to do some
667*7c478bd9Sstevel@tonic-gate 	 * more forks, put the new upcount structure on the front.
668*7c478bd9Sstevel@tonic-gate 	 */
669*7c478bd9Sstevel@tonic-gate 	upc = hupc;
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 	new->up_uid = uid;
672*7c478bd9Sstevel@tonic-gate 	new->up_zoneid = zoneid;
673*7c478bd9Sstevel@tonic-gate 	new->up_count = 1;
674*7c478bd9Sstevel@tonic-gate 	new->up_next = *upc;
675*7c478bd9Sstevel@tonic-gate 
676*7c478bd9Sstevel@tonic-gate 	*upc = new;
677*7c478bd9Sstevel@tonic-gate }
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate /*
680*7c478bd9Sstevel@tonic-gate  * Decrement the number of processes a given uid and zoneid has.
681*7c478bd9Sstevel@tonic-gate  */
682*7c478bd9Sstevel@tonic-gate void
683*7c478bd9Sstevel@tonic-gate upcount_dec(uid_t uid, zoneid_t zoneid)
684*7c478bd9Sstevel@tonic-gate {
685*7c478bd9Sstevel@tonic-gate 	struct	upcount **upc;
686*7c478bd9Sstevel@tonic-gate 	struct	upcount *done;
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
689*7c478bd9Sstevel@tonic-gate 
690*7c478bd9Sstevel@tonic-gate 	upc = &upc_hash[UPC_HASH(uid, zoneid)];
691*7c478bd9Sstevel@tonic-gate 	while ((*upc) != NULL) {
692*7c478bd9Sstevel@tonic-gate 		if ((*upc)->up_uid == uid && (*upc)->up_zoneid == zoneid) {
693*7c478bd9Sstevel@tonic-gate 			(*upc)->up_count--;
694*7c478bd9Sstevel@tonic-gate 			if ((*upc)->up_count == 0) {
695*7c478bd9Sstevel@tonic-gate 				done = *upc;
696*7c478bd9Sstevel@tonic-gate 				*upc = (*upc)->up_next;
697*7c478bd9Sstevel@tonic-gate 				kmem_free(done, sizeof (*done));
698*7c478bd9Sstevel@tonic-gate 			}
699*7c478bd9Sstevel@tonic-gate 			return;
700*7c478bd9Sstevel@tonic-gate 		}
701*7c478bd9Sstevel@tonic-gate 		upc = &(*upc)->up_next;
702*7c478bd9Sstevel@tonic-gate 	}
703*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_PANIC, "decr_upcount-off the end");
704*7c478bd9Sstevel@tonic-gate }
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate /*
707*7c478bd9Sstevel@tonic-gate  * Returns the number of processes a uid has.
708*7c478bd9Sstevel@tonic-gate  * Non-existent uid's are assumed to have no processes.
709*7c478bd9Sstevel@tonic-gate  */
710*7c478bd9Sstevel@tonic-gate int
711*7c478bd9Sstevel@tonic-gate upcount_get(uid_t uid, zoneid_t zoneid)
712*7c478bd9Sstevel@tonic-gate {
713*7c478bd9Sstevel@tonic-gate 	struct	upcount *upc;
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 	upc = upc_hash[UPC_HASH(uid, zoneid)];
718*7c478bd9Sstevel@tonic-gate 	while (upc != NULL) {
719*7c478bd9Sstevel@tonic-gate 		if (upc->up_uid == uid && upc->up_zoneid == zoneid) {
720*7c478bd9Sstevel@tonic-gate 			return (upc->up_count);
721*7c478bd9Sstevel@tonic-gate 		}
722*7c478bd9Sstevel@tonic-gate 		upc = upc->up_next;
723*7c478bd9Sstevel@tonic-gate 	}
724*7c478bd9Sstevel@tonic-gate 	return (0);
725*7c478bd9Sstevel@tonic-gate }
726