kern_synch.c revision 1.31 1 /* $NetBSD: kern_synch.c,v 1.31 1995/03/19 23:44:51 mycroft Exp $ */
2
3 /*-
4 * Copyright (c) 1982, 1986, 1990, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * @(#)kern_synch.c 8.6 (Berkeley) 1/21/94
41 */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/proc.h>
46 #include <sys/kernel.h>
47 #include <sys/buf.h>
48 #include <sys/signalvar.h>
49 #include <sys/resourcevar.h>
50 #include <sys/vmmeter.h>
51 #ifdef KTRACE
52 #include <sys/ktrace.h>
53 #endif
54
55 #include <machine/cpu.h>
56
57 u_char curpriority; /* usrpri of curproc */
58 int lbolt; /* once a second sleep address */
59
60 /*
61 * Force switch among equal priority processes every 100ms.
62 */
63 /* ARGSUSED */
64 void
65 roundrobin(arg)
66 void *arg;
67 {
68
69 need_resched();
70 timeout(roundrobin, NULL, hz / 10);
71 }
72
73 /*
74 * Constants for digital decay and forget:
75 * 90% of (p_estcpu) usage in 5 * loadav time
76 * 95% of (p_pctcpu) usage in 60 seconds (load insensitive)
77 * Note that, as ps(1) mentions, this can let percentages
78 * total over 100% (I've seen 137.9% for 3 processes).
79 *
80 * Note that hardclock updates p_estcpu and p_cpticks independently.
81 *
82 * We wish to decay away 90% of p_estcpu in (5 * loadavg) seconds.
83 * That is, the system wants to compute a value of decay such
84 * that the following for loop:
85 * for (i = 0; i < (5 * loadavg); i++)
86 * p_estcpu *= decay;
87 * will compute
88 * p_estcpu *= 0.1;
89 * for all values of loadavg:
90 *
91 * Mathematically this loop can be expressed by saying:
92 * decay ** (5 * loadavg) ~= .1
93 *
94 * The system computes decay as:
95 * decay = (2 * loadavg) / (2 * loadavg + 1)
96 *
97 * We wish to prove that the system's computation of decay
98 * will always fulfill the equation:
99 * decay ** (5 * loadavg) ~= .1
100 *
101 * If we compute b as:
102 * b = 2 * loadavg
103 * then
104 * decay = b / (b + 1)
105 *
106 * We now need to prove two things:
107 * 1) Given factor ** (5 * loadavg) ~= .1, prove factor == b/(b+1)
108 * 2) Given b/(b+1) ** power ~= .1, prove power == (5 * loadavg)
109 *
110 * Facts:
111 * For x close to zero, exp(x) =~ 1 + x, since
112 * exp(x) = 0! + x**1/1! + x**2/2! + ... .
113 * therefore exp(-1/b) =~ 1 - (1/b) = (b-1)/b.
114 * For x close to zero, ln(1+x) =~ x, since
115 * ln(1+x) = x - x**2/2 + x**3/3 - ... -1 < x < 1
116 * therefore ln(b/(b+1)) = ln(1 - 1/(b+1)) =~ -1/(b+1).
117 * ln(.1) =~ -2.30
118 *
119 * Proof of (1):
120 * Solve (factor)**(power) =~ .1 given power (5*loadav):
121 * solving for factor,
122 * ln(factor) =~ (-2.30/5*loadav), or
123 * factor =~ exp(-1/((5/2.30)*loadav)) =~ exp(-1/(2*loadav)) =
124 * exp(-1/b) =~ (b-1)/b =~ b/(b+1). QED
125 *
126 * Proof of (2):
127 * Solve (factor)**(power) =~ .1 given factor == (b/(b+1)):
128 * solving for power,
129 * power*ln(b/(b+1)) =~ -2.30, or
130 * power =~ 2.3 * (b + 1) = 4.6*loadav + 2.3 =~ 5*loadav. QED
131 *
132 * Actual power values for the implemented algorithm are as follows:
133 * loadav: 1 2 3 4
134 * power: 5.68 10.32 14.94 19.55
135 */
136
137 /* calculations for digital decay to forget 90% of usage in 5*loadav sec */
138 #define loadfactor(loadav) (2 * (loadav))
139 #define decay_cpu(loadfac, cpu) (((loadfac) * (cpu)) / ((loadfac) + FSCALE))
140
141 /* decay 95% of `p_pctcpu' in 60 seconds; see CCPU_SHIFT before changing */
142 fixpt_t ccpu = 0.95122942450071400909 * FSCALE; /* exp(-1/20) */
143
144 /*
145 * If `ccpu' is not equal to `exp(-1/20)' and you still want to use the
146 * faster/more-accurate formula, you'll have to estimate CCPU_SHIFT below
147 * and possibly adjust FSHIFT in "param.h" so that (FSHIFT >= CCPU_SHIFT).
148 *
149 * To estimate CCPU_SHIFT for exp(-1/20), the following formula was used:
150 * 1 - exp(-1/20) ~= 0.0487 ~= 0.0488 == 1 (fixed pt, *11* bits).
151 *
152 * If you dont want to bother with the faster/more-accurate formula, you
153 * can set CCPU_SHIFT to (FSHIFT + 1) which will use a slower/less-accurate
154 * (more general) method of calculating the %age of CPU used by a process.
155 */
156 #define CCPU_SHIFT 11
157
158 /*
159 * Recompute process priorities, every hz ticks.
160 */
161 /* ARGSUSED */
162 void
163 schedcpu(arg)
164 void *arg;
165 {
166 register fixpt_t loadfac = loadfactor(averunnable.ldavg[0]);
167 register struct proc *p;
168 register int s;
169 register unsigned int newcpu;
170
171 wakeup((caddr_t)&lbolt);
172 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
173 /*
174 * Increment time in/out of memory and sleep time
175 * (if sleeping). We ignore overflow; with 16-bit int's
176 * (remember them?) overflow takes 45 days.
177 */
178 p->p_swtime++;
179 if (p->p_stat == SSLEEP || p->p_stat == SSTOP)
180 p->p_slptime++;
181 p->p_pctcpu = (p->p_pctcpu * ccpu) >> FSHIFT;
182 /*
183 * If the process has slept the entire second,
184 * stop recalculating its priority until it wakes up.
185 */
186 if (p->p_slptime > 1)
187 continue;
188 s = splstatclock(); /* prevent state changes */
189 /*
190 * p_pctcpu is only for ps.
191 */
192 #if (FSHIFT >= CCPU_SHIFT)
193 p->p_pctcpu += (hz == 100)?
194 ((fixpt_t) p->p_cpticks) << (FSHIFT - CCPU_SHIFT):
195 100 * (((fixpt_t) p->p_cpticks)
196 << (FSHIFT - CCPU_SHIFT)) / hz;
197 #else
198 p->p_pctcpu += ((FSCALE - ccpu) *
199 (p->p_cpticks * FSCALE / hz)) >> FSHIFT;
200 #endif
201 p->p_cpticks = 0;
202 newcpu = (u_int) decay_cpu(loadfac, p->p_estcpu) + p->p_nice;
203 p->p_estcpu = min(newcpu, UCHAR_MAX);
204 resetpriority(p);
205 if (p->p_priority >= PUSER) {
206 #define PPQ (128 / NQS) /* priorities per queue */
207 if ((p != curproc) &&
208 p->p_stat == SRUN &&
209 (p->p_flag & P_INMEM) &&
210 (p->p_priority / PPQ) != (p->p_usrpri / PPQ)) {
211 remrq(p);
212 p->p_priority = p->p_usrpri;
213 setrunqueue(p);
214 } else
215 p->p_priority = p->p_usrpri;
216 }
217 splx(s);
218 }
219 vmmeter();
220 if (bclnlist != NULL)
221 wakeup((caddr_t)pageproc);
222 timeout(schedcpu, (void *)0, hz);
223 }
224
225 /*
226 * Recalculate the priority of a process after it has slept for a while.
227 * For all load averages >= 1 and max p_estcpu of 255, sleeping for at
228 * least six times the loadfactor will decay p_estcpu to zero.
229 */
230 void
231 updatepri(p)
232 register struct proc *p;
233 {
234 register unsigned int newcpu = p->p_estcpu;
235 register fixpt_t loadfac = loadfactor(averunnable.ldavg[0]);
236
237 if (p->p_slptime > 5 * loadfac)
238 p->p_estcpu = 0;
239 else {
240 p->p_slptime--; /* the first time was done in schedcpu */
241 while (newcpu && --p->p_slptime)
242 newcpu = (int) decay_cpu(loadfac, newcpu);
243 p->p_estcpu = min(newcpu, UCHAR_MAX);
244 }
245 resetpriority(p);
246 }
247
248 /*
249 * We're only looking at 7 bits of the address; everything is
250 * aligned to 4, lots of things are aligned to greater powers
251 * of 2. Shift right by 8, i.e. drop the bottom 256 worth.
252 */
253 #define TABLESIZE 128
254 #define LOOKUP(x) (((long)(x) >> 8) & (TABLESIZE - 1))
255 struct slpque {
256 struct proc *sq_head;
257 struct proc **sq_tailp;
258 } slpque[TABLESIZE];
259
260 /*
261 * During autoconfiguration or after a panic, a sleep will simply
262 * lower the priority briefly to allow interrupts, then return.
263 * The priority to be used (safepri) is machine-dependent, thus this
264 * value is initialized and maintained in the machine-dependent layers.
265 * This priority will typically be 0, or the lowest priority
266 * that is safe for use on the interrupt stack; it can be made
267 * higher to block network software interrupts after panics.
268 */
269 int safepri;
270
271 /*
272 * General sleep call. Suspends the current process until a wakeup is
273 * performed on the specified identifier. The process will then be made
274 * runnable with the specified priority. Sleeps at most timo/hz seconds
275 * (0 means no timeout). If pri includes PCATCH flag, signals are checked
276 * before and after sleeping, else signals are not checked. Returns 0 if
277 * awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a
278 * signal needs to be delivered, ERESTART is returned if the current system
279 * call should be restarted if possible, and EINTR is returned if the system
280 * call should be interrupted by the signal (return EINTR).
281 */
282 int
283 tsleep(ident, priority, wmesg, timo)
284 void *ident;
285 int priority, timo;
286 char *wmesg;
287 {
288 register struct proc *p = curproc;
289 register struct slpque *qp;
290 register s;
291 int sig, catch = priority & PCATCH;
292 extern int cold;
293 void endtsleep __P((void *));
294
295 #ifdef KTRACE
296 if (KTRPOINT(p, KTR_CSW))
297 ktrcsw(p->p_tracep, 1, 0);
298 #endif
299 s = splhigh();
300 if (cold || panicstr) {
301 /*
302 * After a panic, or during autoconfiguration,
303 * just give interrupts a chance, then just return;
304 * don't run any other procs or panic below,
305 * in case this is the idle process and already asleep.
306 */
307 splx(safepri);
308 splx(s);
309 return (0);
310 }
311 #ifdef DIAGNOSTIC
312 if (ident == NULL || p->p_stat != SRUN || p->p_back)
313 panic("tsleep");
314 #endif
315 p->p_wchan = ident;
316 p->p_wmesg = wmesg;
317 p->p_slptime = 0;
318 p->p_priority = priority & PRIMASK;
319 qp = &slpque[LOOKUP(ident)];
320 if (qp->sq_head == 0)
321 qp->sq_head = p;
322 else
323 *qp->sq_tailp = p;
324 *(qp->sq_tailp = &p->p_forw) = 0;
325 if (timo)
326 timeout(endtsleep, (void *)p, timo);
327 /*
328 * We put ourselves on the sleep queue and start our timeout
329 * before calling CURSIG, as we could stop there, and a wakeup
330 * or a SIGCONT (or both) could occur while we were stopped.
331 * A SIGCONT would cause us to be marked as SSLEEP
332 * without resuming us, thus we must be ready for sleep
333 * when CURSIG is called. If the wakeup happens while we're
334 * stopped, p->p_wchan will be 0 upon return from CURSIG.
335 */
336 if (catch) {
337 p->p_flag |= P_SINTR;
338 if (sig = CURSIG(p)) {
339 if (p->p_wchan)
340 unsleep(p);
341 p->p_stat = SRUN;
342 goto resume;
343 }
344 if (p->p_wchan == 0) {
345 catch = 0;
346 goto resume;
347 }
348 } else
349 sig = 0;
350 p->p_stat = SSLEEP;
351 p->p_stats->p_ru.ru_nvcsw++;
352 mi_switch();
353 #ifdef DDB
354 /* handy breakpoint location after process "wakes" */
355 asm(".globl bpendtsleep ; bpendtsleep:");
356 #endif
357 resume:
358 curpriority = p->p_usrpri;
359 splx(s);
360 p->p_flag &= ~P_SINTR;
361 if (p->p_flag & P_TIMEOUT) {
362 p->p_flag &= ~P_TIMEOUT;
363 if (sig == 0) {
364 #ifdef KTRACE
365 if (KTRPOINT(p, KTR_CSW))
366 ktrcsw(p->p_tracep, 0, 0);
367 #endif
368 return (EWOULDBLOCK);
369 }
370 } else if (timo)
371 untimeout(endtsleep, (void *)p);
372 if (catch && (sig != 0 || (sig = CURSIG(p)))) {
373 #ifdef KTRACE
374 if (KTRPOINT(p, KTR_CSW))
375 ktrcsw(p->p_tracep, 0, 0);
376 #endif
377 if (p->p_sigacts->ps_sigintr & sigmask(sig))
378 return (EINTR);
379 return (ERESTART);
380 }
381 #ifdef KTRACE
382 if (KTRPOINT(p, KTR_CSW))
383 ktrcsw(p->p_tracep, 0, 0);
384 #endif
385 return (0);
386 }
387
388 /*
389 * Implement timeout for tsleep.
390 * If process hasn't been awakened (wchan non-zero),
391 * set timeout flag and undo the sleep. If proc
392 * is stopped, just unsleep so it will remain stopped.
393 */
394 void
395 endtsleep(arg)
396 void *arg;
397 {
398 register struct proc *p;
399 int s;
400
401 p = (struct proc *)arg;
402 s = splhigh();
403 if (p->p_wchan) {
404 if (p->p_stat == SSLEEP)
405 setrunnable(p);
406 else
407 unsleep(p);
408 p->p_flag |= P_TIMEOUT;
409 }
410 splx(s);
411 }
412
413 /*
414 * Short-term, non-interruptable sleep.
415 */
416 void
417 sleep(ident, priority)
418 void *ident;
419 int priority;
420 {
421 register struct proc *p = curproc;
422 register struct slpque *qp;
423 register s;
424 extern int cold;
425
426 #ifdef DIAGNOSTIC
427 if (priority > PZERO) {
428 printf("sleep called with priority %d > PZERO, wchan: %p\n",
429 priority, ident);
430 panic("old sleep");
431 }
432 #endif
433 s = splhigh();
434 if (cold || panicstr) {
435 /*
436 * After a panic, or during autoconfiguration,
437 * just give interrupts a chance, then just return;
438 * don't run any other procs or panic below,
439 * in case this is the idle process and already asleep.
440 */
441 splx(safepri);
442 splx(s);
443 return;
444 }
445 #ifdef DIAGNOSTIC
446 if (ident == NULL || p->p_stat != SRUN || p->p_back)
447 panic("sleep");
448 #endif
449 p->p_wchan = ident;
450 p->p_wmesg = NULL;
451 p->p_slptime = 0;
452 p->p_priority = priority;
453 qp = &slpque[LOOKUP(ident)];
454 if (qp->sq_head == 0)
455 qp->sq_head = p;
456 else
457 *qp->sq_tailp = p;
458 *(qp->sq_tailp = &p->p_forw) = 0;
459 p->p_stat = SSLEEP;
460 p->p_stats->p_ru.ru_nvcsw++;
461 #ifdef KTRACE
462 if (KTRPOINT(p, KTR_CSW))
463 ktrcsw(p->p_tracep, 1, 0);
464 #endif
465 mi_switch();
466 #ifdef DDB
467 /* handy breakpoint location after process "wakes" */
468 asm(".globl bpendsleep ; bpendsleep:");
469 #endif
470 #ifdef KTRACE
471 if (KTRPOINT(p, KTR_CSW))
472 ktrcsw(p->p_tracep, 0, 0);
473 #endif
474 curpriority = p->p_usrpri;
475 splx(s);
476 }
477
478 /*
479 * Remove a process from its wait queue
480 */
481 void
482 unsleep(p)
483 register struct proc *p;
484 {
485 register struct slpque *qp;
486 register struct proc **hp;
487 int s;
488
489 s = splhigh();
490 if (p->p_wchan) {
491 hp = &(qp = &slpque[LOOKUP(p->p_wchan)])->sq_head;
492 while (*hp != p)
493 hp = &(*hp)->p_forw;
494 *hp = p->p_forw;
495 if (qp->sq_tailp == &p->p_forw)
496 qp->sq_tailp = hp;
497 p->p_wchan = 0;
498 }
499 splx(s);
500 }
501
502 /*
503 * Make all processes sleeping on the specified identifier runnable.
504 */
505 void
506 wakeup(ident)
507 register void *ident;
508 {
509 register struct slpque *qp;
510 register struct proc *p, **q;
511 int s;
512
513 s = splhigh();
514 qp = &slpque[LOOKUP(ident)];
515 restart:
516 for (q = &qp->sq_head; p = *q; ) {
517 #ifdef DIAGNOSTIC
518 if (p->p_back || p->p_stat != SSLEEP && p->p_stat != SSTOP)
519 panic("wakeup");
520 #endif
521 if (p->p_wchan == ident) {
522 p->p_wchan = 0;
523 *q = p->p_forw;
524 if (qp->sq_tailp == &p->p_forw)
525 qp->sq_tailp = q;
526 if (p->p_stat == SSLEEP) {
527 /* OPTIMIZED EXPANSION OF setrunnable(p); */
528 if (p->p_slptime > 1)
529 updatepri(p);
530 p->p_slptime = 0;
531 p->p_stat = SRUN;
532 if (p->p_flag & P_INMEM)
533 setrunqueue(p);
534 /*
535 * Since curpriority is a user priority,
536 * p->p_priority is always better than
537 * curpriority.
538 */
539 if ((p->p_flag & P_INMEM) == 0)
540 wakeup((caddr_t)&proc0);
541 else
542 need_resched();
543 /* END INLINE EXPANSION */
544 goto restart;
545 }
546 } else
547 q = &p->p_forw;
548 }
549 splx(s);
550 }
551
552 /*
553 * The machine independent parts of mi_switch().
554 * Must be called at splstatclock() or higher.
555 */
556 void
557 mi_switch()
558 {
559 register struct proc *p = curproc; /* XXX */
560 register struct rlimit *rlim;
561 register long s, u;
562 struct timeval tv;
563
564 /*
565 * Compute the amount of time during which the current
566 * process was running, and add that to its total so far.
567 */
568 microtime(&tv);
569 u = p->p_rtime.tv_usec + (tv.tv_usec - runtime.tv_usec);
570 s = p->p_rtime.tv_sec + (tv.tv_sec - runtime.tv_sec);
571 if (u < 0) {
572 u += 1000000;
573 s--;
574 } else if (u >= 1000000) {
575 u -= 1000000;
576 s++;
577 }
578 p->p_rtime.tv_usec = u;
579 p->p_rtime.tv_sec = s;
580
581 /*
582 * Check if the process exceeds its cpu resource allocation.
583 * If over max, kill it. In any case, if it has run for more
584 * than 10 minutes, reduce priority to give others a chance.
585 */
586 rlim = &p->p_rlimit[RLIMIT_CPU];
587 if (s >= rlim->rlim_cur) {
588 if (s >= rlim->rlim_max)
589 psignal(p, SIGKILL);
590 else {
591 psignal(p, SIGXCPU);
592 if (rlim->rlim_cur < rlim->rlim_max)
593 rlim->rlim_cur += 5;
594 }
595 }
596 if (s > 10 * 60 && p->p_ucred->cr_uid && p->p_nice == NZERO) {
597 p->p_nice = NZERO + 4;
598 resetpriority(p);
599 }
600
601 /*
602 * Pick a new current process and record its start time.
603 */
604 cnt.v_swtch++;
605 cpu_switch(p);
606 microtime(&runtime);
607 }
608
609 /*
610 * Initialize the (doubly-linked) run queues
611 * to be empty.
612 */
613 void
614 rqinit()
615 {
616 register int i;
617
618 for (i = 0; i < NQS; i++)
619 qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
620 }
621
622 /*
623 * Change process state to be runnable,
624 * placing it on the run queue if it is in memory,
625 * and awakening the swapper if it isn't in memory.
626 */
627 void
628 setrunnable(p)
629 register struct proc *p;
630 {
631 register int s;
632
633 s = splhigh();
634 switch (p->p_stat) {
635 case 0:
636 case SRUN:
637 case SZOMB:
638 default:
639 panic("setrunnable");
640 case SSTOP:
641 case SSLEEP:
642 unsleep(p); /* e.g. when sending signals */
643 break;
644
645 case SIDL:
646 break;
647 }
648 p->p_stat = SRUN;
649 if (p->p_flag & P_INMEM)
650 setrunqueue(p);
651 splx(s);
652 if (p->p_slptime > 1)
653 updatepri(p);
654 p->p_slptime = 0;
655 if ((p->p_flag & P_INMEM) == 0)
656 wakeup((caddr_t)&proc0);
657 else if (p->p_priority < curpriority)
658 need_resched();
659 }
660
661 /*
662 * Compute the priority of a process when running in user mode.
663 * Arrange to reschedule if the resulting priority is better
664 * than that of the current process.
665 */
666 void
667 resetpriority(p)
668 register struct proc *p;
669 {
670 register unsigned int newpriority;
671
672 newpriority = PUSER + p->p_estcpu / 4 + 2 * p->p_nice;
673 newpriority = min(newpriority, MAXPRI);
674 p->p_usrpri = newpriority;
675 if (newpriority < curpriority)
676 need_resched();
677 }
678
679 #ifdef DDB
680 void
681 db_show_all_procs(addr, haddr, count, modif)
682 long addr;
683 int haddr;
684 int count;
685 char *modif;
686 {
687 int map = modif[0] == 'm';
688 int doingzomb = 0;
689 struct proc *p, *pp;
690
691 p = allproc.lh_first;
692 db_printf(" pid proc addr %s comm wchan\n",
693 map ? "map " : "uid ppid pgrp flag stat em ");
694 while (p != 0) {
695 pp = p->p_pptr;
696 if (p->p_stat) {
697 db_printf("%5d %06x %06x ",
698 p->p_pid, p, p->p_addr);
699 if (map)
700 db_printf("%06x %s ",
701 p->p_vmspace, p->p_comm);
702 else
703 db_printf("%3d %5d %5d %06x %d %d %s ",
704 p->p_cred->p_ruid, pp ? pp->p_pid : -1,
705 p->p_pgrp->pg_id, p->p_flag, p->p_stat,
706 p->p_emul, p->p_comm);
707 if (p->p_wchan) {
708 if (p->p_wmesg)
709 db_printf("%s ", p->p_wmesg);
710 db_printf("%x", p->p_wchan);
711 }
712 db_printf("\n");
713 }
714 p = p->p_list.le_next;
715 if (p == 0 && doingzomb == 0) {
716 doingzomb = 1;
717 p = zombproc.lh_first;
718 }
719 }
720 }
721 #endif
722