+
+/*
+ * Look up a code for a specified speed in a conversion table;
+ * used by drivers to map software speed values to hardware parameters.
+ */
+ttspeedtab(speed, table)
+ register struct speedtab *table;
+{
+
+ for ( ; table->sp_speed != -1; table++)
+ if (table->sp_speed == speed)
+ return (table->sp_code);
+ return (-1);
+}
+
+/*
+ * set tty hi and low water marks
+ *
+ * Try to arrange the dynamics so there's about one second
+ * from hi to low water.
+ *
+ */
+ttsetwater(tp)
+ struct tty *tp;
+{
+ register cps = tp->t_ospeed / 10;
+ register x;
+
+#define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x))
+ tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT);
+ x += cps;
+ x = clamp(x, TTMAXHIWAT, TTMINHIWAT);
+ tp->t_hiwat = roundup(x, CBSIZE);
+#undef clamp
+}
+
+/*
+ * Report on state of foreground process group.
+ */
+ttyinfo(tp)
+ register struct tty *tp;
+{
+ register struct proc *p, *pick;
+ struct timeval utime, stime;
+ int tmp;
+
+ if (ttycheckoutq(tp,0) == 0)
+ return;
+
+ /* Print load average. */
+ tmp = (averunnable[0] * 100 + FSCALE / 2) >> FSHIFT;
+ ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
+
+ if (tp->t_session == NULL)
+ ttyprintf(tp, "not a controlling terminal\n");
+ else if (tp->t_pgrp == NULL)
+ ttyprintf(tp, "no foreground process group\n");
+ else if ((p = tp->t_pgrp->pg_mem) == NULL)
+ ttyprintf(tp, "empty foreground process group\n");
+ else {
+ /* Pick interesting process. */
+ for (pick = NULL; p != NULL; p = p->p_pgrpnxt)
+ if (proc_compare(pick, p))
+ pick = p;
+
+ ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
+ pick->p_stat == SRUN ? "running" :
+ pick->p_wmesg ? pick->p_wmesg : "iowait");
+
+ /*
+ * Lock out clock if process is running; get user/system
+ * cpu time.
+ */
+ if (curproc == pick)
+ tmp = splclock();
+ utime = pick->p_utime;
+ stime = pick->p_stime;
+ if (curproc == pick)
+ splx(tmp);
+
+ /* Print user time. */
+ ttyprintf(tp, "%d.%02du ",
+ utime.tv_sec, (utime.tv_usec + 5000) / 10000);
+
+ /* Print system time. */
+ ttyprintf(tp, "%d.%02ds ",
+ stime.tv_sec, (stime.tv_usec + 5000) / 10000);
+
+#define pgtok(a) (((a) * NBPG) / 1024)
+ /* Print percentage cpu, resident set size. */
+ tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT;
+ ttyprintf(tp, "%d%% %dk\n",
+ tmp / 100, pgtok(pick->p_vmspace->vm_rssize));
+ }
+ tp->t_rocount = 0; /* so pending input will be retyped if BS */
+}
+
+/*
+ * Returns 1 if p2 is "better" than p1
+ *
+ * The algorithm for picking the "interesting" process is thus:
+ *
+ * 1) (Only foreground processes are eligable - implied)
+ * 2) Runnable processes are favored over anything
+ * else. The runner with the highest cpu
+ * utilization is picked (p_cpu). Ties are
+ * broken by picking the highest pid.
+ * 3 Next, the sleeper with the shortest sleep
+ * time is favored. With ties, we pick out
+ * just "short-term" sleepers (SSINTR == 0).
+ * Further ties are broken by picking the highest
+ * pid.
+ *
+ */
+#define isrun(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
+#define TESTAB(a, b) ((a)<<1 | (b))
+#define ONLYA 2
+#define ONLYB 1
+#define BOTH 3
+
+static int
+proc_compare(p1, p2)
+ register struct proc *p1, *p2;
+{
+
+ if (p1 == NULL)
+ return (1);
+ /*
+ * see if at least one of them is runnable
+ */
+ switch (TESTAB(isrun(p1), isrun(p2))) {
+ case ONLYA:
+ return (0);
+ case ONLYB:
+ return (1);
+ case BOTH:
+ /*
+ * tie - favor one with highest recent cpu utilization
+ */
+ if (p2->p_cpu > p1->p_cpu)
+ return (1);
+ if (p1->p_cpu > p2->p_cpu)
+ return (0);
+ return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
+ }
+ /*
+ * weed out zombies
+ */
+ switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
+ case ONLYA:
+ return (1);
+ case ONLYB:
+ return (0);
+ case BOTH:
+ return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
+ }
+ /*
+ * pick the one with the smallest sleep time
+ */
+ if (p2->p_slptime > p1->p_slptime)
+ return (0);
+ if (p1->p_slptime > p2->p_slptime)
+ return (1);
+ /*
+ * favor one sleeping in a non-interruptible sleep
+ */
+ if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0)
+ return (1);
+ if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0)
+ return (0);
+ return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
+}
+
+/*
+ * Output char to tty; console putchar style.
+ */
+tputchar(c, tp)
+ int c;
+ struct tty *tp;
+{
+ register s = spltty();
+
+ if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) {
+ if (c == '\n')
+ (void) ttyoutput('\r', tp);
+ (void) ttyoutput(c, tp);
+ ttstart(tp);
+ splx(s);
+ return (0);
+ }
+ splx(s);
+ return (-1);
+}
+
+/*
+ * Sleep on chan, returning ERESTART if tty changed
+ * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT)
+ * reported by tsleep. If the tty is revoked, restarting a pending
+ * call will redo validation done at the start of the call.
+ */
+ttysleep(tp, chan, pri, wmesg, timo)
+ struct tty *tp;
+ caddr_t chan;
+ int pri;
+ char *wmesg;
+ int timo;
+{
+ int error;
+ short gen = tp->t_gen;
+
+ if (error = tsleep(chan, pri, wmesg, timo))
+ return (error);
+ if (tp->t_gen != gen)
+ return (ERESTART);
+ return (0);
+}