procset.c revision 6618:96ff3dcc3f84
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27/*	  All Rights Reserved  	*/
28
29
30#pragma ident	"%Z%%M%	%I%	%E% SMI"	/* from SVr4.0 1.25 */
31
32#include <sys/types.h>
33#include <sys/sysmacros.h>
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/vfs.h>
37#include <sys/cred.h>
38#include <sys/vnode.h>
39#include <sys/file.h>
40#include <sys/errno.h>
41#include <sys/kmem.h>
42#include <sys/user.h>
43#include <sys/buf.h>
44#include <sys/var.h>
45#include <sys/conf.h>
46#include <sys/debug.h>
47#include <sys/proc.h>
48#include <sys/signal.h>
49#include <sys/siginfo.h>
50#include <sys/acct.h>
51#include <sys/procset.h>
52#include <sys/cmn_err.h>
53#include <sys/fault.h>
54#include <sys/syscall.h>
55#include <sys/ucontext.h>
56#include <sys/procfs.h>
57#include <sys/session.h>
58#include <sys/task.h>
59#include <sys/project.h>
60#include <sys/pool.h>
61#include <sys/zone.h>
62#include <sys/contract/process_impl.h>
63
64id_t	getmyid(idtype_t);
65int	checkprocset(procset_t *);
66static	kthread_t *getlwpptr(id_t);
67int	procinset(proc_t *, procset_t *);
68static	int lwpinset(proc_t *, procset_t *, kthread_t *, int *);
69
70/*
71 * The dotoprocs function locates the process(es) specified
72 * by the procset structure pointed to by psp.  funcp points to a
73 * function which dotoprocs will call for each process in the
74 * specified set.  The arguments to this function will be a pointer
75 * to the current process from the set and arg.
76 * If the called function returns -1, it means that processing of the
77 * procset should stop and a normal (non-error) return should be made
78 * to the caller of dotoprocs.
79 * If the called function returns any other non-zero value the search
80 * is terminated and the function's return value is returned to
81 * the caller of dotoprocs.  This will normally be an error code.
82 * Otherwise, dotoprocs will return zero after processing the entire
83 * process set unless no processes were found in which case ESRCH will
84 * be returned.
85 */
86int
87dotoprocs(procset_t *psp, int (*funcp)(), char *arg)
88{
89	proc_t	*prp;	/* A process from the set */
90	int	error;
91	int	nfound;	/* Nbr of processes found.	*/
92	proc_t	*lastprp;	/* Last proc found.	*/
93
94	ASSERT(funcp != NULL);
95
96	/*
97	 * Check that the procset_t is valid.
98	 */
99	error = checkprocset(psp);
100	if (error) {
101		return (error);
102	}
103	/*
104	 * Check for the special value P_MYID in either operand
105	 * and replace it with the correct value.  We don't check
106	 * for an error return from getmyid() because the idtypes
107	 * have been validated by the checkprocset() call above.
108	 */
109	mutex_enter(&pidlock);
110	if (psp->p_lid == P_MYID) {
111		psp->p_lid = getmyid(psp->p_lidtype);
112	}
113	if (psp->p_rid == P_MYID) {
114		psp->p_rid = getmyid(psp->p_ridtype);
115	}
116
117	/*
118	 * If psp only acts on a single proc, we can reduce pidlock hold time
119	 * by avoiding a needless scan of the entire proc list.  Although
120	 * there are many procset_t combinations which might boil down to a
121	 * single proc, the most common case is an AND operation where one
122	 * side is a specific pid, and the other side is P_ALL, so that is
123	 * the case for which we will provide a fast path.  Other cases could
124	 * be added in a similar fashion if they were to become significant
125	 * pidlock bottlenecks.
126	 *
127	 * Perform the check symmetrically:  either the left or right side may
128	 * specify a pid, with the opposite side being 'all'.
129	 */
130	if (psp->p_op == POP_AND) {
131		if (((psp->p_lidtype == P_PID) && (psp->p_ridtype == P_ALL)) ||
132		    ((psp->p_ridtype == P_PID) && (psp->p_lidtype == P_ALL))) {
133			id_t pid;
134
135			pid = (psp->p_lidtype == P_PID) ?
136			    psp->p_lid : psp->p_rid;
137			if (((prp = prfind((pid_t)pid)) == NULL) ||
138			    (prp->p_stat == SIDL || prp->p_stat == SZOMB ||
139			    prp->p_tlist == NULL || prp->p_flag & SSYS)) {
140				/*
141				 * Specified proc doesn't exist or should
142				 * not be operated on.
143				 * Don't need to make HASZONEACCESS check
144				 * here since prfind() takes care of that.
145				 */
146				mutex_exit(&pidlock);
147				return (ESRCH);
148			}
149			/*
150			 * Operate only on the specified proc.  It's okay
151			 * if it's init.
152			 */
153			error = (*funcp)(prp, arg);
154			mutex_exit(&pidlock);
155			if (error == -1)
156				error = 0;
157			return (error);
158		}
159	}
160
161	nfound = 0;
162	error  = 0;
163
164	for (prp = practive; prp != NULL; prp = prp->p_next) {
165		/*
166		 * If caller is in a non-global zone, skip processes
167		 * in other zones.
168		 */
169		if (!HASZONEACCESS(curproc, prp->p_zone->zone_id))
170			continue;
171
172		/*
173		 * Ignore this process if it's coming or going,
174		 * if it's a system process or if it's not in
175		 * the given procset_t.
176		 */
177		if (prp->p_stat == SIDL || prp->p_stat == SZOMB)
178			continue;
179
180		mutex_enter(&prp->p_lock);
181		if (prp->p_flag & SSYS || procinset(prp, psp) == 0) {
182			mutex_exit(&prp->p_lock);
183		} else {
184			mutex_exit(&prp->p_lock);
185			nfound++;
186			lastprp = prp;
187			if (prp != proc_init) {
188				error = (*funcp)(prp, arg);
189				if (error == -1) {
190					mutex_exit(&pidlock);
191					return (0);
192				} else if (error) {
193					mutex_exit(&pidlock);
194					return (error);
195				}
196			}
197		}
198	}
199	if (nfound == 0) {
200		mutex_exit(&pidlock);
201		return (ESRCH);
202	}
203	if (nfound == 1 && lastprp == proc_init)
204		error = (*funcp)(lastprp, arg);
205	if (error == -1)
206		error = 0;
207	mutex_exit(&pidlock);
208	return (error);
209}
210
211/*
212 * Check if a procset_t is valid.  Return zero or an errno.
213 */
214int
215checkprocset(procset_t *psp)
216{
217	switch (psp->p_lidtype) {
218	case P_LWPID:
219	case P_PID:
220	case P_PPID:
221	case P_PGID:
222	case P_SID:
223	case P_TASKID:
224	case P_CID:
225	case P_UID:
226	case P_GID:
227	case P_PROJID:
228	case P_POOLID:
229	case P_ZONEID:
230	case P_CTID:
231	case P_ALL:
232		break;
233	default:
234		return (EINVAL);
235	}
236
237	switch (psp->p_ridtype) {
238	case P_LWPID:
239	case P_PID:
240	case P_PPID:
241	case P_PGID:
242	case P_SID:
243	case P_TASKID:
244	case P_CID:
245	case P_UID:
246	case P_GID:
247	case P_PROJID:
248	case P_POOLID:
249	case P_ZONEID:
250	case P_CTID:
251	case P_ALL:
252		break;
253	default:
254		return (EINVAL);
255	}
256
257	switch (psp->p_op) {
258	case POP_DIFF:
259	case POP_AND:
260	case POP_OR:
261	case POP_XOR:
262		break;
263	default:
264		return (EINVAL);
265	}
266
267	return (0);
268}
269
270/*
271 * procinset returns 1 if the process pointed to by pp is in the process
272 * set specified by psp, otherwise 0 is returned. A process that is
273 * exiting, by which we mean that its p_tlist is NULL, cannot belong
274 * to any set; pp's p_lock must be held across the call to this function.
275 * The caller should ensure that the process does not belong to the SYS
276 * scheduling class.
277 *
278 * This function expects to be called with a valid procset_t.
279 * The set should be checked using checkprocset() before calling
280 * this function.
281 */
282int
283procinset(proc_t *pp, procset_t *psp)
284{
285	int	loperand = 0;
286	int	roperand = 0;
287	int	lwplinproc = 0;
288	int	lwprinproc = 0;
289	kthread_t	*tp = proctot(pp);
290
291	ASSERT(MUTEX_HELD(&pp->p_lock));
292
293	if (tp == NULL)
294		return (0);
295
296	switch (psp->p_lidtype) {
297
298	case P_LWPID:
299		if (pp == ttoproc(curthread))
300			if (getlwpptr(psp->p_lid) != NULL)
301				lwplinproc++;
302		break;
303
304	case P_PID:
305		if (pp->p_pid == psp->p_lid)
306			loperand++;
307		break;
308
309	case P_PPID:
310		if (pp->p_ppid == psp->p_lid)
311			loperand++;
312		break;
313
314	case P_PGID:
315		if (pp->p_pgrp == psp->p_lid)
316			loperand++;
317		break;
318
319	case P_SID:
320		mutex_enter(&pp->p_splock);
321		if (pp->p_sessp->s_sid == psp->p_lid)
322			loperand++;
323		mutex_exit(&pp->p_splock);
324		break;
325
326	case P_CID:
327		ASSERT(tp != NULL);
328		/* This case is broken for now. Need to be fixed XXX */
329		if (tp->t_cid == psp->p_lid)
330			/*
331			 * if (checkcid(psp->p_lid))
332			 */
333			loperand++;
334		break;
335
336	case P_TASKID:
337		if (pp->p_task->tk_tkid == psp->p_lid)
338			loperand++;
339		break;
340
341	case P_UID:
342		mutex_enter(&pp->p_crlock);
343		if (crgetuid(pp->p_cred) == psp->p_lid)
344			loperand++;
345		mutex_exit(&pp->p_crlock);
346		break;
347
348	case P_GID:
349		mutex_enter(&pp->p_crlock);
350		if (crgetgid(pp->p_cred) == psp->p_lid)
351			loperand++;
352		mutex_exit(&pp->p_crlock);
353		break;
354
355	case P_PROJID:
356		if (pp->p_task->tk_proj->kpj_id == psp->p_lid)
357			loperand++;
358		break;
359
360	case P_POOLID:
361		if (pp->p_pool->pool_id == psp->p_lid)
362			loperand++;
363		break;
364
365	case P_ZONEID:
366		if (pp->p_zone->zone_id == psp->p_lid)
367			loperand++;
368		break;
369
370	case P_CTID:
371		if (PRCTID(pp) == psp->p_lid)
372			loperand++;
373		break;
374
375	case P_ALL:
376		loperand++;
377		break;
378
379	default:
380#ifdef DEBUG
381		cmn_err(CE_WARN, "procinset called with bad set");
382		return (0);
383#else
384		return (0);
385#endif
386	}
387
388	switch (psp->p_ridtype) {
389
390	case P_LWPID:
391		if (pp == ttoproc(curthread))
392			if (getlwpptr(psp->p_rid) != NULL)
393				lwprinproc++;
394		break;
395
396	case P_PID:
397		if (pp->p_pid == psp->p_rid)
398			roperand++;
399		break;
400
401	case P_PPID:
402		if (pp->p_ppid == psp->p_rid)
403			roperand++;
404		break;
405
406	case P_PGID:
407		if (pp->p_pgrp == psp->p_rid)
408			roperand++;
409		break;
410
411	case P_SID:
412		mutex_enter(&pp->p_splock);
413		if (pp->p_sessp->s_sid == psp->p_rid)
414			roperand++;
415		mutex_exit(&pp->p_splock);
416		break;
417
418	case P_TASKID:
419		if (pp->p_task->tk_tkid == psp->p_rid)
420			roperand++;
421		break;
422
423	case P_CID:
424		ASSERT(tp != NULL);
425		/* This case is broken for now. Need to be fixed XXX */
426		if (tp->t_cid == psp->p_rid)
427			/*
428			 * if (checkcid(psp->p_rid))
429			 */
430			roperand++;
431		break;
432
433	case P_UID:
434		mutex_enter(&pp->p_crlock);
435		if (crgetuid(pp->p_cred) == psp->p_rid)
436			roperand++;
437		mutex_exit(&pp->p_crlock);
438		break;
439
440	case P_GID:
441		mutex_enter(&pp->p_crlock);
442		if (crgetgid(pp->p_cred) == psp->p_rid)
443			roperand++;
444		mutex_exit(&pp->p_crlock);
445		break;
446
447	case P_PROJID:
448		if (pp->p_task->tk_proj->kpj_id == psp->p_rid)
449			roperand++;
450		break;
451
452	case P_POOLID:
453		if (pp->p_pool->pool_id == psp->p_rid)
454			roperand++;
455		break;
456
457	case P_ZONEID:
458		if (pp->p_zone->zone_id == psp->p_rid)
459			roperand++;
460		break;
461
462	case P_CTID:
463		if (PRCTID(pp) == psp->p_rid)
464			roperand++;
465		break;
466
467	case P_ALL:
468		roperand++;
469		break;
470
471	default:
472#ifdef DEBUG
473		cmn_err(CE_WARN, "procinset called with bad set");
474		return (0);
475#else
476		return (0);
477#endif
478	}
479
480	switch (psp->p_op) {
481
482	case POP_DIFF:
483		if (loperand && !lwprinproc && !roperand)
484			return (1);
485		else
486			return (0);
487
488	case POP_AND:
489		if (loperand && roperand)
490			return (1);
491		else
492			return (0);
493
494	case POP_OR:
495		if (loperand || roperand)
496			return (1);
497		else
498			return (0);
499
500	case POP_XOR:
501		if ((loperand && !lwprinproc && !roperand) ||
502		    (roperand && !lwplinproc && !loperand))
503			return (1);
504		else
505			return (0);
506
507	default:
508#ifdef DEBUG
509		cmn_err(CE_WARN, "procinset called with bad set");
510		return (0);
511#else
512		return (0);
513#endif
514	}
515	/* NOTREACHED */
516}
517
518/*
519 * lwpinset returns 1 if the thread pointed to
520 * by tp is in the process set specified by psp and is not in
521 * the sys scheduling class - otherwise 0 is returned.
522 *
523 * This function expects to be called with a valid procset_t.
524 * The set should be checked using checkprocset() before calling
525 * this function.
526 */
527int
528lwpinset(proc_t *pp, procset_t *psp, kthread_t *tp, int *done)
529{
530	int	loperand = 0;
531	int	roperand = 0;
532	int	lwplinset  = 0;
533	int	lwprinset  = 0;
534
535	ASSERT(ttoproc(tp) == pp);
536
537	/*
538	 * If process is in the sys class return (0).
539	 */
540	if (proctot(pp)->t_cid == 0) {
541		return (0);
542	}
543
544	switch (psp->p_lidtype) {
545
546	case P_LWPID:
547		if (tp->t_tid == psp->p_lid)
548			lwplinset ++;
549		break;
550
551	case P_PID:
552		if (pp->p_pid == psp->p_lid)
553			loperand++;
554		break;
555
556	case P_PPID:
557		if (pp->p_ppid == psp->p_lid)
558			loperand++;
559		break;
560
561	case P_PGID:
562		if (pp->p_pgrp == psp->p_lid)
563			loperand++;
564		break;
565
566	case P_SID:
567		mutex_enter(&pp->p_splock);
568		if (pp->p_sessp->s_sid == psp->p_lid)
569			loperand++;
570		mutex_exit(&pp->p_splock);
571		break;
572
573	case P_TASKID:
574		if (pp->p_task->tk_tkid == psp->p_lid)
575			loperand++;
576		break;
577
578	case P_CID:
579		if (tp->t_cid == psp->p_lid)
580			loperand++;
581		break;
582
583	case P_UID:
584		mutex_enter(&pp->p_crlock);
585		if (crgetuid(pp->p_cred) == psp->p_lid)
586			loperand++;
587		mutex_exit(&pp->p_crlock);
588		break;
589
590	case P_GID:
591		mutex_enter(&pp->p_crlock);
592		if (crgetgid(pp->p_cred) == psp->p_lid)
593			loperand++;
594		mutex_exit(&pp->p_crlock);
595		break;
596
597	case P_PROJID:
598		if (pp->p_task->tk_proj->kpj_id == psp->p_lid)
599			loperand++;
600		break;
601
602	case P_POOLID:
603		if (pp->p_pool->pool_id == psp->p_lid)
604			loperand++;
605		break;
606
607	case P_ZONEID:
608		if (pp->p_zone->zone_id == psp->p_lid)
609			loperand++;
610		break;
611
612	case P_CTID:
613		if (PRCTID(pp) == psp->p_lid)
614			loperand++;
615		break;
616
617	case P_ALL:
618		loperand++;
619		break;
620
621	default:
622#ifdef DEBUG
623		cmn_err(CE_WARN, "lwpinset called with bad set");
624		return (0);
625#else
626		return (0);
627#endif
628	}
629
630	switch (psp->p_ridtype) {
631
632	case P_LWPID:
633		if (tp->t_tid == psp->p_rid)
634			lwprinset ++;
635		break;
636
637	case P_PID:
638		if (pp->p_pid == psp->p_rid)
639			roperand++;
640		break;
641
642	case P_PPID:
643		if (pp->p_ppid == psp->p_rid)
644			roperand++;
645		break;
646
647	case P_PGID:
648		if (pp->p_pgrp == psp->p_rid)
649			roperand++;
650		break;
651
652	case P_SID:
653		mutex_enter(&pp->p_splock);
654		if (pp->p_sessp->s_sid == psp->p_rid)
655			roperand++;
656		mutex_exit(&pp->p_splock);
657		break;
658
659	case P_TASKID:
660		if (pp->p_task->tk_tkid == psp->p_rid)
661			roperand++;
662		break;
663
664	case P_CID:
665		if (tp->t_cid == psp->p_rid)
666			roperand++;
667		break;
668
669	case P_UID:
670		mutex_enter(&pp->p_crlock);
671		if (crgetuid(pp->p_cred) == psp->p_rid)
672			roperand++;
673		mutex_exit(&pp->p_crlock);
674		break;
675
676	case P_GID:
677		mutex_enter(&pp->p_crlock);
678		if (crgetgid(pp->p_cred) == psp->p_rid)
679			roperand++;
680		mutex_exit(&pp->p_crlock);
681		break;
682
683	case P_PROJID:
684		if (pp->p_task->tk_proj->kpj_id == psp->p_rid)
685			roperand++;
686		break;
687
688	case P_POOLID:
689		if (pp->p_pool->pool_id == psp->p_rid)
690			roperand++;
691		break;
692
693	case P_ZONEID:
694		if (pp->p_zone->zone_id == psp->p_rid)
695			roperand++;
696		break;
697
698	case P_CTID:
699		if (PRCTID(pp) == psp->p_rid)
700			roperand++;
701		break;
702
703	case P_ALL:
704		roperand++;
705		break;
706
707	default:
708#ifdef DEBUG
709		cmn_err(CE_WARN, "lwpinset called with bad set");
710		return (0);
711#else
712		return (0);
713#endif
714	}
715
716	if (lwplinset && lwprinset)
717		*done = 1;
718
719	switch (psp->p_op) {
720
721	case POP_DIFF:
722		if ((loperand || lwplinset) && !(lwprinset || roperand))
723			return (1);
724		else
725			return (0);
726
727	case POP_AND:
728		if ((loperand || lwplinset) && (roperand || lwprinset))
729			return (1);
730		else
731			return (0);
732
733	case POP_OR:
734		if (loperand || roperand || lwplinset || lwprinset)
735			return (1);
736		else
737			return (0);
738
739	case POP_XOR:
740		if (((loperand || lwplinset) &&
741		    !(lwprinset || roperand)) ||
742		    ((roperand || lwprinset) &&
743		    !(lwplinset || loperand)))
744			return (1);
745		else
746			return (0);
747
748	default:
749#ifdef DEBUG
750		cmn_err(CE_WARN, "lwpinset called with bad set");
751		return (0);
752#else
753		return (0);
754#endif
755	}
756	/* NOTREACHED */
757}
758/*
759 * Check for common cases of procsets which specify only the
760 * current process.  cur_inset_only() returns B_TRUE when
761 * the current process is the only one in the set.  B_FALSE
762 * is returned to indicate that this may not be the case.
763 */
764boolean_t
765cur_inset_only(procset_t *psp)
766{
767	if (((psp->p_lidtype == P_PID &&
768	    (psp->p_lid == P_MYID ||
769	    psp->p_lid == ttoproc(curthread)->p_pid)) ||
770	    ((psp->p_lidtype == P_LWPID) &&
771	    (psp->p_lid == P_MYID ||
772	    psp->p_lid == curthread->t_tid))) &&
773	    psp->p_op == POP_AND && psp->p_ridtype == P_ALL)
774		return (B_TRUE);
775
776	if (((psp->p_ridtype == P_PID &&
777	    (psp->p_rid == P_MYID ||
778	    psp->p_rid == ttoproc(curthread)->p_pid)) ||
779	    ((psp->p_ridtype == P_LWPID) &&
780	    (psp->p_rid == P_MYID ||
781	    psp->p_rid == curthread->t_tid))) &&
782	    psp->p_op == POP_AND && psp->p_lidtype == P_ALL)
783		return (B_TRUE);
784
785	return (B_FALSE);
786}
787
788id_t
789getmyid(idtype_t idtype)
790{
791	proc_t	*pp;
792	uid_t uid;
793	gid_t gid;
794	pid_t sid;
795
796	pp = ttoproc(curthread);
797
798	switch (idtype) {
799	case P_LWPID:
800		return (curthread->t_tid);
801
802	case P_PID:
803		return (pp->p_pid);
804
805	case P_PPID:
806		return (pp->p_ppid);
807
808	case P_PGID:
809		return (pp->p_pgrp);
810
811	case P_SID:
812		mutex_enter(&pp->p_splock);
813		sid = pp->p_sessp->s_sid;
814		mutex_exit(&pp->p_splock);
815		return (sid);
816
817	case P_TASKID:
818		return (pp->p_task->tk_tkid);
819
820	case P_CID:
821		return (curthread->t_cid);
822
823	case P_UID:
824		mutex_enter(&pp->p_crlock);
825		uid = crgetuid(pp->p_cred);
826		mutex_exit(&pp->p_crlock);
827		return (uid);
828
829	case P_GID:
830		mutex_enter(&pp->p_crlock);
831		gid = crgetgid(pp->p_cred);
832		mutex_exit(&pp->p_crlock);
833		return (gid);
834
835	case P_PROJID:
836		return (pp->p_task->tk_proj->kpj_id);
837
838	case P_POOLID:
839		return (pp->p_pool->pool_id);
840
841	case P_ZONEID:
842		return (pp->p_zone->zone_id);
843
844	case P_CTID:
845		return (PRCTID(pp));
846
847	case P_ALL:
848		/*
849		 * The value doesn't matter for P_ALL.
850		 */
851		return (0);
852
853	default:
854		return (-1);
855	}
856}
857
858static kthread_t *
859getlwpptr(id_t id)
860{
861	proc_t		*p;
862	kthread_t	*t;
863
864	ASSERT(MUTEX_HELD(&(ttoproc(curthread)->p_lock)));
865
866	if (id == P_MYID)
867		t = curthread;
868	else {
869		p = ttoproc(curthread);
870		t = idtot(p, id);
871	}
872
873	return (t);
874}
875
876/*
877 * The dotolwp function locates the LWP(s) specified by the procset structure
878 * pointed to by psp.  If funcp is non-NULL then it points to a function
879 * which dotolwp will call for each LWP in the specified set.
880 * LWPIDs specified in the procset structure always refer to lwps in curproc.
881 * The arguments for this function must be "char *arg", and "kthread_t *tp",
882 * where tp is a pointer to the current thread from the set.
883 * Note that these arguments are passed to the function in reversed order
884 * than the order of arguments passed by dotoprocs() to its callback function.
885 * Also note that there are two separate cases where this routine returns zero.
886 * In the first case no mutex is grabbed, in the second the p_lock mutex
887 * is NOT RELEASED. The priocntl code is expecting this behaviour.
888 */
889int
890dotolwp(procset_t *psp, int (*funcp)(), char *arg)
891{
892	int		error = 0;
893	int		nfound = 0;
894	kthread_t	*tp;
895	proc_t		*pp;
896	int		done = 0;
897
898	/*
899	 * Check that the procset_t is valid.
900	 */
901	error = checkprocset(psp);
902	if (error) {
903		return (error);
904	}
905
906	mutex_enter(&pidlock);
907
908	/*
909	 * Check for the special value P_MYID in either operand
910	 * and replace it with the correct value.  We don't check
911	 * for an error return from getmyid() because the idtypes
912	 * have been validated by the checkprocset() call above.
913	 */
914	if (psp->p_lid == P_MYID) {
915		psp->p_lid = getmyid(psp->p_lidtype);
916	}
917	if (psp->p_rid == P_MYID) {
918		psp->p_rid = getmyid(psp->p_ridtype);
919	}
920
921	pp = ttoproc(curthread);
922
923	mutex_enter(&pp->p_lock);
924	if (procinset(pp, psp) ||
925	    (tp = pp->p_tlist) == NULL) {
926		mutex_exit(&pp->p_lock);
927		mutex_exit(&pidlock);
928		return (0);
929	}
930	do {
931		if (lwpinset(pp, psp, tp, &done)) {
932			nfound ++;
933			error = (*funcp)(arg, tp);
934			if (error) {
935				mutex_exit(&pp->p_lock);
936				mutex_exit(&pidlock);
937				return (error);
938			}
939		}
940	} while (((tp = tp->t_forw) != pp->p_tlist) && !done);
941
942	if (nfound == 0) {
943		mutex_exit(&pp->p_lock);
944		mutex_exit(&pidlock);
945		return (ESRCH);
946	}
947
948	mutex_exit(&pidlock);
949	return (error);
950}
951