This is m_sunos5.c in view mode; [Download] [Up]
/*
* top - a top users display for Unix
*
* SYNOPSIS: Any Sun running SunOS 5.x (Solaris 2.x)
*
* DESCRIPTION:
* This is the machine-dependent module for SunOS 5.x (Solaris 2).
* There is some support for MP architectures.
* This makes top work on the following systems:
* SunOS 5.0 (not tested)
* SunOS 5.1
* SunOS 5.2
* SunOS 5.3
*
* Tested on a SPARCclassic with SunOS 5.1, using gcc-2.3.3, and
* SPARCsystem 600 with SunOS 5.2, using Sun C
*
* LIBS: -lelf -lkvm
*
* CFLAGS: -DHAVE_GETOPT
*
*
* AUTHORS: Torsten Kasch <torsten@techfak.uni-bielefeld.de>
* Robert Boucher <boucher@sofkin.ca>
* CONTRIBUTORS: Marc Cohen <marc@aai.com>
* Charles Hedrick <hedrick@geneva.rutgers.edu>
* William L. Jones <jones@chpc>
* Petri Kutvonen <kutvonen@cs.helsinki.fi>
* Casper Dik <casper@fwi.uva.nl>
* Tim Pugh <tpugh@oce.orst.edu>
*/
#define _KMEMUSER
#include "top.h"
#include "machine.h"
#include "utils.h"
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <dirent.h>
#include <nlist.h>
#include <string.h>
#include <kvm.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/signal.h>
#include <sys/fault.h>
#include <sys/sysinfo.h>
#include <sys/sysmacros.h>
#include <sys/syscall.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/procfs.h>
#include <sys/vm.h>
#include <sys/var.h>
#include <sys/cpuvar.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/priocntl.h>
#include <sys/tspriocntl.h>
#include <sys/processor.h>
#include <vm/anon.h>
#include <math.h>
#define UNIX "/dev/ksyms"
#define KMEM "/dev/kmem"
#define PROCFS "/proc"
#define CPUSTATES 5
#ifndef PRIO_MIN
#define PRIO_MIN -20
#endif
#ifndef PRIO_MAX
#define PRIO_MAX 20
#endif
#ifndef FSCALE
#define FSHIFT 8 /* bits to right of fixed binary point */
#define FSCALE (1<<FSHIFT)
#endif /* FSCALE */
#define loaddouble(la) ((double)(la) / FSCALE)
#define dbl_align(x) (((unsigned long)(x)+(sizeof(double)-1)) & \
~(sizeof(double)-1))
#ifdef SOLARIS24
/*
* snarfed from <sys/procfs.h>:
* The following percent numbers are 16-bit binary
* fractions [0 .. 1] with the binary point to the
* right of the high-order bit (one == 0x8000)
*/
#define percent_cpu(pp) (((double)pp->pr_pctcpu)/0x8000*100)
#define weighted_cpu(pp) (*(double *)dbl_align(pp->pr_filler))
#else
#define percent_cpu(pp) (*(double *)dbl_align(&pp->pr_filler[0]))
#define weighted_cpu(pp) (*(double *)dbl_align(&pp->pr_filler[2]))
#endif
/* NOTE: this next macro assumes that PAGESHIFT is 12---i.e.: a page is 4K.
This is a blatantly general assumption and ought to be fixed */
#define pagetok(size) ((size)<<2)
/* definitions for indices in the nlist array */
#define X_AVENRUN 0
#define X_MPID 1
#define X_CPU 2
#define X_V 3
#define X_NPROC 4
#define X_ANONINFO 5
#define X_FREEMEM 6
#define X_MAXMEM 7
#define X_AVAILRMEM 8
#define X_SWAPFS_MINFREE 9
#define X_NCPUS 10
static struct nlist nlst[] =
{
{"avenrun"}, /* 0 */
{"mpid"}, /* 1 */
{"cpu"}, /* 2 */
{"v"}, /* 3 */
{"nproc"}, /* 4 */
{"anoninfo"}, /* 5 */
{"freemem"}, /* 6 */
{"maxmem"}, /* 7 */
{"availrmem"}, /* 8 */
{"swapfs_minfree"}, /* 9 */
{"ncpus"}, /* 10 */
{0}
};
static unsigned long avenrun_offset;
static unsigned long mpid_offset;
static unsigned long *cpu_offset;
static unsigned long nproc_offset;
static unsigned long freemem_offset;
static unsigned long maxmem_offset;
static unsigned long availrmem_offset;
static unsigned long swapfs_minfree_offset;
static unsigned long anoninfo_offset;
/* get_process_info passes back a handle. This is what it looks like: */
struct handle
{
struct prpsinfo **next_proc;/* points to next valid proc pointer */
int remaining; /* number of pointers remaining */
};
/*
* Structure for keeping track of CPU times from last time around
* the program. We keep these things in a hash table, which is
* recreated at every cycle.
*/
struct oldproc
{
pid_t oldpid;
double oldtime;
double oldpct;
};
int oldprocs; /* size of table */
#define HASH(x) ((x << 1) % oldprocs)
/*
* GCC assumes that all doubles are aligned. Unfortunately it
* doesn't round up the structure size to be a multiple of 8.
* Thus we'll get a coredump when going through array. The
* following is a size rounded up to 8.
*/
#define PRPSINFOSIZE dbl_align(sizeof(struct prpsinfo))
/*
* These definitions control the format of the per-process area
*/
static char header[] =
" PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
/* 0123456 -- field to fill in starts at header+6 */
#define UNAME_START 6
#define Proc_format \
"%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %s"
/* process state names for the "STATE" column of the display */
/* the extra nulls in the string "run" are for adding a slash and
the processor number when needed */
char *state_abbrev[] =
{"", "sleep", "run", "zombie", "stop", "start", "cpu", "swap"};
int process_states[8];
char *procstatenames[] =
{
"", " sleeping, ", " running, ", " zombie, ", " stopped, ",
" starting, ", " on cpu, ", " swapped, ",
NULL
};
int cpu_states[CPUSTATES];
char *cpustatenames[] =
{"idle", "user", "kernel", "iowait", "swap", NULL};
/* these are for detailing the memory statistics */
int memory_stats[5];
char *memorynames[] =
{"K real, ", "K active, ", "K free, ", "K swap, ", "K free swap", NULL};
kvm_t *kd;
static DIR *procdir;
static int nproc;
static int ncpus;
/* these are for keeping track of the proc array */
static int bytes;
static struct prpsinfo *pbase;
static struct prpsinfo **pref;
static struct oldproc *oldbase;
/* useful externals */
extern int errno;
extern char *sys_errlist[];
extern char *myname;
extern int check_nlist ();
extern int gettimeofday ();
extern int getkval ();
extern void perror ();
extern void getptable ();
extern void quit ();
extern int nlist ();
int
machine_init (struct statics *statics)
{
static struct var v;
struct oldproc *op, *endbase;
int i;
int offset;
processor_info_t pi;
/* perform the kvm_open */
kd = kvm_open (NULL, NULL, NULL, O_RDONLY, "top");
/* turn off super user privs */
seteuid(getuid());
/* fill in the statics information */
statics->procstate_names = procstatenames;
statics->cpustate_names = cpustatenames;
statics->memory_names = memorynames;
/* test kvm_open return value */
if (kd == NULL)
{
perror ("kvm_open");
return (-1);
}
if (kvm_nlist (kd, nlst) < 0)
{
perror ("kvm_nlist");
return (-1);
}
if (check_nlist (nlst) != 0)
return (-1);
/* NPROC Tuning parameter for max number of processes */
(void) getkval (nlst[X_V].n_value, &v, sizeof (struct var), nlst[X_V].n_name);
nproc = v.v_proc;
/* stash away certain offsets for later use */
mpid_offset = nlst[X_MPID].n_value;
nproc_offset = nlst[X_NPROC].n_value;
avenrun_offset = nlst[X_AVENRUN].n_value;
anoninfo_offset = nlst[X_ANONINFO].n_value;
freemem_offset = nlst[X_FREEMEM].n_value;
maxmem_offset = nlst[X_MAXMEM].n_value;
availrmem_offset = nlst[X_AVAILRMEM].n_value;
swapfs_minfree_offset = nlst[X_SWAPFS_MINFREE].n_value;
(void) getkval (nlst[X_NCPUS].n_value, (int *) (&ncpus),
sizeof (ncpus), "ncpus");
cpu_offset = (unsigned long *) malloc (ncpus * sizeof (unsigned long));
for (i = offset = 0; i < ncpus; offset += sizeof(unsigned long)) {
(void) getkval (nlst[X_CPU].n_value + offset,
&cpu_offset[i], sizeof (unsigned long),
nlst[X_CPU].n_name );
if (cpu_offset[i] != 0)
i++;
}
/* allocate space for proc structure array and array of pointers */
bytes = nproc * PRPSINFOSIZE;
pbase = (struct prpsinfo *) malloc (bytes);
pref = (struct prpsinfo **) malloc (nproc * sizeof (struct prpsinfo *));
oldbase = (struct oldproc *) malloc (2 * nproc * sizeof (struct oldproc));
/* Just in case ... */
if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL
|| oldbase == (struct oldproc *) NULL)
{
fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);
return (-1);
}
oldprocs = 2 * nproc;
endbase = oldbase + oldprocs;
for (op = oldbase; op < endbase; op++)
op->oldpid = -1;
if (!(procdir = opendir (PROCFS)))
{
(void) fprintf (stderr, "Unable to open %s\n", PROCFS);
return (-1);
}
if (chdir (PROCFS))
{ /* handy for later on when we're reading it */
(void) fprintf (stderr, "Unable to chdir to %s\n", PROCFS);
return (-1);
}
/* all done! */
return (0);
}
char *
format_header (register char *uname_field)
{
register char *ptr;
ptr = header + UNAME_START;
while (*uname_field != '\0')
*ptr++ = *uname_field++;
return (header);
}
void
get_system_info (struct system_info *si)
{
long avenrun[3];
struct cpu cpu;
static int freemem;
static int maxmem;
static int availrmem;
static int swapfs_minfree;
struct anoninfo anoninfo;
static long cp_time[CPUSTATES];
static long cp_old[CPUSTATES];
static long cp_diff[CPUSTATES];
register int j, i;
/* get the cp_time array */
for (j = 0; j < CPUSTATES; j++)
cp_time[j] = 0L;
for (i = 0; i < ncpus; i++)
if (cpu_offset[i] != 0)
{
(void) getkval (cpu_offset[i], &cpu, sizeof (struct cpu), "cpu");
for (j = 0; j < CPUSTATES-1; j++)
cp_time[j] += (long) cpu.cpu_stat.cpu_sysinfo.cpu[j];
cp_time[CPUSTATES-2] += (long) cpu.cpu_stat.cpu_sysinfo.wait[W_IO] +
(long) cpu.cpu_stat.cpu_sysinfo.wait[W_PIO];
cp_time[CPUSTATES-1] += (long) cpu.cpu_stat.cpu_sysinfo.wait[W_SWAP];
}
/* convert cp_time counts to percentages */
(void) percentages (CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
/* get mpid -- process id of last process */
(void) getkval (mpid_offset, &(si->last_pid), sizeof (si->last_pid), "mpid");
/* get load average array */
(void) getkval (avenrun_offset, (int *) avenrun, sizeof (avenrun), "avenrun");
/* convert load averages to doubles */
for (i = 0; i < 3; i++)
si->load_avg[i] = loaddouble (avenrun[i]);
/* get system wide main memory usage structure */
(void) getkval (freemem_offset, (int *) (&freemem), sizeof (freemem), "freemem");
(void) getkval (maxmem_offset, (int *) (&maxmem), sizeof (maxmem), "maxmem");
memory_stats[0] = pagetok (maxmem);
memory_stats[1] = 0;
memory_stats[2] = pagetok (freemem);
(void) getkval (anoninfo_offset, (int *) (&anoninfo), sizeof (anoninfo), "anoninfo");
(void) getkval (availrmem_offset, (int *) (&availrmem), sizeof (availrmem), "availrmem");
(void) getkval (swapfs_minfree_offset, (int *) (&swapfs_minfree), sizeof (swapfs_minfree), "swapfs_minfree");
memory_stats[3] = pagetok (anoninfo.ani_resv);
memory_stats[4] = pagetok (MAX ((int) (anoninfo.ani_max - anoninfo.ani_resv), 0) + availrmem - swapfs_minfree);
/* set arrays and strings */
si->cpustates = cpu_states;
si->memory = memory_stats;
}
static struct handle handle;
caddr_t
get_process_info (
struct system_info *si,
struct process_select *sel,
int (*compare) ())
{
register int i;
register int total_procs;
register int active_procs;
register struct prpsinfo **prefp;
register struct prpsinfo *pp;
/* these are copied out of sel for speed */
int show_idle;
int show_system;
int show_uid;
/* Get current number of processes */
(void) getkval (nproc_offset, (int *) (&nproc), sizeof (nproc), "nproc");
/* read all the proc structures */
getptable (pbase);
/* get a pointer to the states summary array */
si->procstates = process_states;
/* set up flags which define what we are going to select */
show_idle = sel->idle;
show_system = sel->system;
show_uid = sel->uid != -1;
/* count up process states and get pointers to interesting procs */
total_procs = 0;
active_procs = 0;
(void) memset (process_states, 0, sizeof (process_states));
prefp = pref;
for (pp = pbase, i = 0; i < nproc;
i++, pp = (struct prpsinfo *) ((char *) pp + PRPSINFOSIZE))
{
/*
* Place pointers to each valid proc structure in pref[].
* Process slots that are actually in use have a non-zero
* status field. Processes with SSYS set are system
* processes---these get ignored unless show_sysprocs is set.
*/
if (pp->pr_state != 0 &&
(show_system || ((pp->pr_flag & SSYS) == 0)))
{
total_procs++;
process_states[pp->pr_state]++;
if ((!pp->pr_zomb) &&
(show_idle || percent_cpu (pp) || (pp->pr_state == SRUN) || (pp->pr_state == SONPROC)) &&
(!show_uid || pp->pr_uid == (uid_t) sel->uid))
{
*prefp++ = pp;
active_procs++;
}
}
}
/* if requested, sort the "interesting" processes */
if (compare != NULL)
qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *), compare);
/* remember active and total counts */
si->p_total = total_procs;
si->p_active = active_procs;
/* pass back a handle */
handle.next_proc = pref;
handle.remaining = active_procs;
return ((caddr_t) & handle);
}
char fmt[MAX_COLS]; /* static area where result is built */
char *
format_next_process (
caddr_t handle,
char *(*get_userid) ())
{
register struct prpsinfo *pp;
struct handle *hp;
register long cputime;
register double pctcpu;
/* find and remember the next proc structure */
hp = (struct handle *) handle;
pp = *(hp->next_proc++);
hp->remaining--;
/* get the cpu usage and calculate the cpu percentages */
cputime = pp->pr_time.tv_sec;
pctcpu = percent_cpu (pp);
/* format this entry */
sprintf (fmt,
Proc_format,
pp->pr_pid,
(*get_userid) (pp->pr_uid),
pp->pr_pri - PZERO,
pp->pr_nice - NZERO,
format_k(pp->pr_bysize / 1024),
format_k(pp->pr_byrssize / 1024),
state_abbrev[pp->pr_state],
format_time(cputime),
weighted_cpu (pp),
pctcpu,
pp->pr_fname);
/* return the result */
return (fmt);
}
/*
* check_nlist(nlst) - checks the nlist to see if any symbols were not
* found. For every symbol that was not found, a one-line
* message is printed to stderr. The routine returns the
* number of symbols NOT found.
*/
int
check_nlist (register struct nlist *nlst)
{
register int i;
/* check to see if we got ALL the symbols we requested */
/* this will write one line to stderr for every symbol not found */
i = 0;
while (nlst->n_name != NULL)
{
if (nlst->n_type == 0)
{
/* this one wasn't found */
fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
i = 1;
}
nlst++;
}
return (i);
}
/*
* getkval(offset, ptr, size, refstr) - get a value out of the kernel.
* "offset" is the byte offset into the kernel for the desired value,
* "ptr" points to a buffer into which the value is retrieved,
* "size" is the size of the buffer (and the object to retrieve),
* "refstr" is a reference string used when printing error meessages,
* if "refstr" starts with a '!', then a failure on read will not
* be fatal (this may seem like a silly way to do things, but I
* really didn't want the overhead of another argument).
*
*/
int
getkval (unsigned long offset,
int *ptr,
int size,
char *refstr)
{
if (kvm_read (kd, offset, (char *) ptr, size) != size)
{
if (*refstr == '!')
{
return (0);
}
else
{
fprintf (stderr, "top: kvm_read for %s: %s\n", refstr, sys_errlist[errno]);
quit (23);
}
}
return (1);
}
/* comparison routine for qsort */
/*
* proc_compare - comparison function for "qsort"
* Compares the resource consumption of two processes using five
* distinct keys. The keys (in descending order of importance) are:
* percent cpu, cpu ticks, state, resident set size, total virtual
* memory usage. The process states are ordered as follows (from least
* to most important): WAIT, zombie, sleep, stop, start, run. The
* array declaration below maps a process state index into a number
* that reflects this ordering.
*/
unsigned char sorted_state[] =
{
0, /* not used */
3, /* sleep */
6, /* run */
2, /* zombie */
4, /* stop */
5, /* start */
7, /* run on a processor */
1 /* being swapped (WAIT) */
};
int
proc_compare (
struct prpsinfo **pp1,
struct prpsinfo **pp2)
{
register struct prpsinfo *p1;
register struct prpsinfo *p2;
register long result;
double dresult;
/* remove one level of indirection */
p1 = *pp1;
p2 = *pp2;
/* compare percent cpu (pctcpu) */
dresult = percent_cpu (p2) - percent_cpu (p1);
if (dresult != 0.0)
{
if (dresult > 0.0)
return 1;
else
return -1;
}
{
/* use cpticks to break the tie */
if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0)
{
/* use process state to break the tie */
if ((result = (long) (sorted_state[p2->pr_state] -
sorted_state[p1->pr_state])) == 0)
{
/* use priority to break the tie */
if ((result = p2->pr_oldpri - p1->pr_oldpri) == 0)
{
/* use resident set size (rssize) to break the tie */
if ((result = p2->pr_rssize - p1->pr_rssize) == 0)
{
/* use total memory to break the tie */
result = (p2->pr_size - p1->pr_size);
}
}
}
}
}
return (result);
}
/*
get process table
V.4 only has a linked list of processes so we want to follow that
linked list, get all the process structures, and put them in our own
table
*/
void
getptable (struct prpsinfo *baseptr)
{
struct prpsinfo *currproc; /* pointer to current proc structure */
int numprocs = 0;
int i;
struct dirent *direntp;
struct oldproc *op;
static struct timeval lasttime =
{0, 0};
struct timeval thistime;
double timediff;
double alpha, beta;
struct oldproc *endbase;
char d_name[12];
gettimeofday (&thistime);
/*
* To avoid divides, we keep times in nanoseconds. This is
* scaled by 1e7 rather than 1e9 so that when we divide we
* get percent.
*/
if (lasttime.tv_sec)
timediff = ((double) thistime.tv_sec * 1.0e7 +
((double) thistime.tv_usec * 10.0)) -
((double) lasttime.tv_sec * 1.0e7 +
((double) lasttime.tv_usec * 10.0));
else
timediff = 1.0e7;
/*
* constants for exponential average. avg = alpha * new + beta * avg
* The goal is 50% decay in 30 sec. However if the sample period
* is greater than 30 sec, there's not a lot we can do.
*/
if (timediff < 30.0e7)
{
alpha = 0.5 * (timediff / 30.0e7);
beta = 1.0 - alpha;
}
else
{
alpha = 0.5;
beta = 0.5;
}
endbase = oldbase + oldprocs;
currproc = baseptr;
/* before reading /proc files, turn on root privs */
/* (we don't care if this fails since it will be caught later) */
seteuid(0);
rewinddir (procdir);
while( (direntp = readdir (procdir)) != NULL)
{
int fd;
if(direntp->d_ino <= 64)
continue;
/* use file name = (direntp->d_ino - 64), not direntp->d_name.
* 1/12/96 tpugh
*/
sprintf(d_name,"%i",direntp->d_ino - 64);
if ((fd = open (d_name, O_RDONLY)) < 0)
{
perror("top getptable open");
continue;
}
if (ioctl (fd, PIOCPSINFO, currproc) < 0)
{
(void) close (fd);
continue;
}
/*
* SVr4 doesn't keep track of CPU% in the kernel, so we have
* to do our own. See if we've heard of this process before.
* If so, compute % based on CPU since last time.
*/
op = oldbase + HASH (currproc->pr_pid);
while (1)
{
if (op->oldpid == -1) /* not there */
break;
if (op->oldpid == currproc->pr_pid)
{ /* found old data */
#ifndef SOLARIS24
percent_cpu (currproc) =
((currproc->pr_time.tv_sec * 1.0e9 +
currproc->pr_time.tv_nsec)
- op->oldtime) / timediff;
#endif
weighted_cpu (currproc) =
op->oldpct * beta + percent_cpu (currproc) * alpha;
break;
}
op++; /* try next entry in hash table */
if (op == endbase) /* table wrapped around */
op = oldbase;
}
/* Otherwise, it's new, so use all of its CPU time */
if (op->oldpid == -1)
{
#ifdef SOLARIS24
weighted_cpu (currproc) =
percent_cpu (currproc);
#else
if (lasttime.tv_sec)
{
percent_cpu (currproc) =
(currproc->pr_time.tv_sec * 1.0e9 +
currproc->pr_time.tv_nsec) / timediff;
weighted_cpu (currproc) =
percent_cpu (currproc);
}
else
{ /* first screen -- no difference is possible */
percent_cpu (currproc) = 0.0;
weighted_cpu (currproc) = 0.0;
}
#endif
}
numprocs++;
currproc = (struct prpsinfo *) ((char *) currproc + PRPSINFOSIZE);
(void) close (fd);
}
/* turn off root privs */
seteuid(getuid());
if (nproc != numprocs)
nproc = numprocs;
/*
* Save current CPU time for next time around
* For the moment recreate the hash table each time, as the code
* is easier that way.
*/
oldprocs = 2 * nproc;
endbase = oldbase + oldprocs;
for (op = oldbase; op < endbase; op++)
op->oldpid = -1;
for (i = 0, currproc = baseptr;
i < nproc;
i++, currproc = (struct prpsinfo *) ((char *) currproc + PRPSINFOSIZE))
{
/* find an empty spot */
op = oldbase + HASH (currproc->pr_pid);
while (1)
{
if (op->oldpid == -1)
break;
op++;
if (op == endbase)
op = oldbase;
}
op->oldpid = currproc->pr_pid;
op->oldtime = (currproc->pr_time.tv_sec * 1.0e9 +
currproc->pr_time.tv_nsec);
op->oldpct = weighted_cpu (currproc);
}
lasttime = thistime;
}
/*
* proc_owner(pid) - returns the uid that owns process "pid", or -1 if
* the process does not exist.
* It is EXTREMLY IMPORTANT that this function work correctly.
* If top runs setuid root (as in SVR4), then this function
* is the only thing that stands in the way of a serious
* security problem. It validates requests for the "kill"
* and "renice" commands.
*/
uid_t
proc_owner (pid_t pid)
{
register struct prpsinfo *p;
int i;
for (i = 0, p = pbase; i < nproc;
i++, p = (struct prpsinfo *) ((char *) p + PRPSINFOSIZE)) {
if (p->pr_pid == pid)
return (p->pr_uid);
}
return (-1);
}
int
setpriority (int dummy, int who, int niceval)
{
int scale;
int prio;
pcinfo_t pcinfo;
pcparms_t pcparms;
tsparms_t *tsparms;
strcpy (pcinfo.pc_clname, "TS");
if (priocntl (0, 0, PC_GETCID, (caddr_t) & pcinfo) == -1)
return (-1);
prio = niceval;
if (prio > PRIO_MAX)
prio = PRIO_MAX;
else if (prio < PRIO_MIN)
prio = PRIO_MIN;
tsparms = (tsparms_t *) pcparms.pc_clparms;
scale = ((tsinfo_t *) pcinfo.pc_clinfo)->ts_maxupri;
tsparms->ts_uprilim = tsparms->ts_upri = -(scale * prio) / 20;
pcparms.pc_cid = pcinfo.pc_cid;
if (priocntl (P_PID, who, PC_SETPARMS, (caddr_t) & pcparms) == -1)
return (-1);
return (0);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.